From 8d705fbd69bffea51caccf1dd0fc6b6f7b90d9ae Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Mon, 16 Aug 2021 22:55:32 -0500 Subject: [PATCH 001/146] rename task to just build (#826) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9c6e68b99..2d25ca4d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: build on: pull_request jobs: - build-and-deploy: + build: runs-on: ubuntu-latest steps: - name: Checkout From c8da58e90231c821b0b48a651adc77005a96c325 Mon Sep 17 00:00:00 2001 From: James Schloss Date: Wed, 18 Aug 2021 13:23:26 +0900 Subject: [PATCH 002/146] fixing order of function arguments (#827) --- .../approximate_counting/code/julia/approximate_counting.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contents/approximate_counting/code/julia/approximate_counting.jl b/contents/approximate_counting/code/julia/approximate_counting.jl index 9a10eae59..5e1fa86c3 100644 --- a/contents/approximate_counting/code/julia/approximate_counting.jl +++ b/contents/approximate_counting/code/julia/approximate_counting.jl @@ -52,10 +52,10 @@ end @testset "Counting Tests, 100 trials" begin println("testing 1,000, a = 30, 1% error") - test_approximate_count(0.1, 100, 1000, 30) + test_approximate_count(100, 1000, 30, 0.1) println("testing 12,345, a = 10, 1% error") - test_approximate_count(0.1, 100, 12345, 10) + test_approximate_count(100, 12345, 10, 0.1) # Note: with a lower a, we need more trials, so a higher % error here. println("testing 222,222, a = 0.5, 10% error") - test_approximate_count(0.1, 100, 222222, 0.5) + test_approximate_count(100, 222222, 0.5, 0.2) end From fb01675a12e567c6a92d6ab6a74c019e7d02dee1 Mon Sep 17 00:00:00 2001 From: James Schloss Date: Wed, 18 Aug 2021 13:23:57 +0900 Subject: [PATCH 003/146] adding kotlin back to the chapter for the euclidean algorithm (#825) --- contents/euclidean_algorithm/euclidean_algorithm.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contents/euclidean_algorithm/euclidean_algorithm.md b/contents/euclidean_algorithm/euclidean_algorithm.md index 035e7ae81..82aa64a2a 100644 --- a/contents/euclidean_algorithm/euclidean_algorithm.md +++ b/contents/euclidean_algorithm/euclidean_algorithm.md @@ -210,6 +210,8 @@ Here's a video on the Euclidean algorithm: [import, lang="c_cpp"](code/c++/euclidean.cpp) {% sample lang="java" %} [import, lang="java"](code/java/EuclideanAlgo.java) +{% sample lang="kotlin" %} +[import, lang="kotlin"](code/kotlin/Euclidean.kt) {% sample lang="js" %} [import, lang="javascript"](code/javascript/euclidean_example.js) {% sample lang="lisp" %} From 62f1c5ff16f5d8ef50691dab001f04e6a401183a Mon Sep 17 00:00:00 2001 From: Ken Power Date: Wed, 18 Aug 2021 00:35:58 -0400 Subject: [PATCH 004/146] Comptus implementation in Scala (#808) * Comptus implementation in Scala * fixed filename in chapter --- .../computus/code/scala/gauss_easter.scala | 58 +++++++++++++++++++ contents/computus/computus.md | 2 + 2 files changed, 60 insertions(+) create mode 100644 contents/computus/code/scala/gauss_easter.scala diff --git a/contents/computus/code/scala/gauss_easter.scala b/contents/computus/code/scala/gauss_easter.scala new file mode 100644 index 000000000..01f5a4c30 --- /dev/null +++ b/contents/computus/code/scala/gauss_easter.scala @@ -0,0 +1,58 @@ +object GaussEaster { + def computus(year : Int, servois: Boolean = false): String = { + + // Year's position on the 19 year metonic cycle + val a = year % 19 + + // Century index + val k = (year / 100).toInt + + // Shift of metonic cycle, add a day offset every 300 years + val p = ((13 + 8 * k) / 25).toInt + + // Correction for non-observed leap days + val q = (k / 4).toInt + + // Correction to starting point of calculation each century + val M = (15 - p + k - q) % 30 + + // Number of days from March 21st until the full moon + val d = (19 * a + M) % 30 + + // Returning if user wants value for Servois' table + if (servois) + return s"${(21 + d) % 31}" + + // Finding the next Sunday + // Century-based offset in weekly calculation + val N = (4 + k - q) % 7 + + // Correction for leap days + val b = year % 4 + val c = year % 7 + + // Days from d to next Sunday + var e = (2 * b + 4 * c + 6 * d + N) % 7 + + // Historical corrections for April 26 and 25 + if ((d == 29 && e == 6) || (d == 28 && e == 6 && a > 10)) { + e = -1 + } + + // Determination of the correct month for Easter + if (22 + d + e > 31) + s"April ${d + e - 9}" + else + s"March ${22 + d + e}" + } + + def main(args: Array[String]): Unit = { + println("The following are the dates of the Paschal full moon (using " + + "Servois notation) and the date of Easter for 2020-2030 AD:\n" + + "Year\tServois number\tEaster\n") + + for( year <- 2020 to 2030){ + println(s"$year \t\t ${computus(year, true)} \t${computus(year)}") + } + } +} \ No newline at end of file diff --git a/contents/computus/computus.md b/contents/computus/computus.md index 6be87f2f6..31071d5f1 100644 --- a/contents/computus/computus.md +++ b/contents/computus/computus.md @@ -320,6 +320,8 @@ For now, we have the code outputting a tuple of $$d$$ and $$e$$, so users can us [import, lang:"lisp"](code/clisp/gauss-easter.lisp) {% sample lang="nim" %} [import, lang:"nim"](code/nim/gauss_easter.nim) +{% sample lang="scala" %} +[import, lang:"scala"](code/scala/gauss_easter.scala) {% endmethod %} From 77a8f06ac71ffd060a5526fecdf49b5a8bd6a75e Mon Sep 17 00:00:00 2001 From: stormofice <58337328+stormofice@users.noreply.github.com> Date: Mon, 23 Aug 2021 06:16:00 +0200 Subject: [PATCH 005/146] Fix typo in barnsley/julia (#829) --- contents/barnsley/code/julia/barnsley.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/barnsley/code/julia/barnsley.jl b/contents/barnsley/code/julia/barnsley.jl index 87aeb2bc3..779d7a13a 100644 --- a/contents/barnsley/code/julia/barnsley.jl +++ b/contents/barnsley/code/julia/barnsley.jl @@ -22,7 +22,7 @@ end # This is a general function to simulate a chaos game # n is the number of iterations -# initial_location is the the starting point of the chaos game +# initial_location is the starting point of the chaos game # hutchinson_op is the set of functions to iterate through # probabilities is the set of probabilities corresponding to the likelihood # of choosing their corresponding function in hutchinson_op From 2797d85ae0348395f403cc2f3ec13e5bc1bb3d90 Mon Sep 17 00:00:00 2001 From: Progyan Bhattacharya Date: Mon, 23 Aug 2021 10:00:28 +0530 Subject: [PATCH 006/146] feat(ts): stack and queue implementation (#775) --- .../code/typescript/queue.ts | 52 +++++++++++++++++++ .../code/typescript/stack.ts | 52 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 contents/stacks_and_queues/code/typescript/queue.ts create mode 100644 contents/stacks_and_queues/code/typescript/stack.ts diff --git a/contents/stacks_and_queues/code/typescript/queue.ts b/contents/stacks_and_queues/code/typescript/queue.ts new file mode 100644 index 000000000..59d9c8321 --- /dev/null +++ b/contents/stacks_and_queues/code/typescript/queue.ts @@ -0,0 +1,52 @@ +interface IQueue { + /** + * `dequeue` removes first element from the queue and returns the same + */ + dequeue(): T; + /** + * `enqueue` adds element to last of the queue and returns the size + */ + enqueue(data: T): number; + /** + * `size` return size or length of the queue + */ + size(): number; + /** + * `front` returns first element of the queue + */ + front(): T; +} + +class Queue implements IQueue { + private readonly list: Array = []; + + public enqueue(data: T) { + return this.list.push(data); + } + + public dequeue() { + return this.list.shift(); + } + + public size() { + return this.list.length; + } + + public front() { + return this.list[0]; + } +} + +function exampleQueue() { + const numberQueue = new Queue(); + + numberQueue.enqueue(4); + numberQueue.enqueue(5); + numberQueue.enqueue(9); + + console.log(numberQueue.dequeue()); + console.log(numberQueue.size()); + console.log(numberQueue.front()); +} + +exampleQueue(); diff --git a/contents/stacks_and_queues/code/typescript/stack.ts b/contents/stacks_and_queues/code/typescript/stack.ts new file mode 100644 index 000000000..58b38ac40 --- /dev/null +++ b/contents/stacks_and_queues/code/typescript/stack.ts @@ -0,0 +1,52 @@ +interface IStack { + /** + * `pop` removes last element from the stack and returns the same + */ + pop(): T; + /** + * `push` adds element to last of the stack and returns the size + */ + push(data: T): number; + /** + * `size` return size or length of the stack + */ + size(): number; + /** + * `top` returns last element of the stack + */ + top(): T; +} + +class Stack implements IStack { + private readonly list: Array = []; + + public push(data: T) { + return this.list.push(data); + } + + public pop() { + return this.list.pop(); + } + + public size() { + return this.list.length; + } + + public top() { + return this.list[this.list.length - 1]; + } +} + +function exampleStack() { + const numberStack = new Stack(); + + numberStack.push(4); + numberStack.push(5); + numberStack.push(9); + + console.log(numberStack.pop()); + console.log(numberStack.size()); + console.log(numberStack.top()); +} + +exampleStack(); From 841cb1132cd528950e46039a69be26cfbc7d5f59 Mon Sep 17 00:00:00 2001 From: Ridham Zalawadia <33592738+Ridham177@users.noreply.github.com> Date: Mon, 23 Aug 2021 20:38:02 -0700 Subject: [PATCH 007/146] Convolutions of Images 2d Python implementation (#819) * Added python code for convolutions 2d. Modified 2d.md file to include added python code. * Updated list comprehension code to numpy code. Changed if statements to not use escape character * fixed minor errors * solved minor errors * Changed circle size. Removed test values for x and y * Update contents/convolutions/2d/2d.md Co-authored-by: James Schloss * Update contents/convolutions/2d/2d.md Co-authored-by: James Schloss * added name to contributors.md * resolved conflict * removed name from contributors.md. will add next commit * added name to contributors.md Co-authored-by: James Schloss --- CONTRIBUTORS.md | 1 + contents/convolutions/2d/2d.md | 8 ++ .../code/python/2d_convolution.py | 122 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 contents/convolutions/code/python/2d_convolution.py diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 29d9e8e09..d594ad218 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -56,3 +56,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Ishaan Verma - Delphi1024 - ntindle +- Ridham177 diff --git a/contents/convolutions/2d/2d.md b/contents/convolutions/2d/2d.md index d026c8a52..7fc21aeb6 100644 --- a/contents/convolutions/2d/2d.md +++ b/contents/convolutions/2d/2d.md @@ -21,6 +21,8 @@ In code, a two-dimensional convolution might look like this: {% method %} {% sample lang="jl" %} [import:4-28, lang:"julia"](../code/julia/2d_convolution.jl) +{% sample lang="py" %} +[import:5-19, lang:"python"](../code/python/2d_convolution.py) {% endmethod %} This is very similar to what we have shown in previous sections; however, it essentially requires four iterable dimensions because we need to iterate through each axis of the output domain *and* the filter. @@ -48,6 +50,8 @@ At this stage, it is important to write some code, so we will generate a simple {% method %} {% sample lang="jl" %} [import:30-47, lang:"julia"](../code/julia/2d_convolution.jl) +{% sample lang="py" %} +[import:21-33, lang:"python"](../code/python/2d_convolution.py) {% endmethod %} Though it is entirely possible to create a Gaussian kernel whose standard deviation is independent on the kernel size, we have decided to enforce a relation between the two in this chapter. @@ -135,6 +139,8 @@ In code, the Sobel operator involves first finding the operators in $$x$$ and $$ {% method %} {% sample lang="jl" %} [import:49-63, lang:"julia"](../code/julia/2d_convolution.jl) +{% sample lang="py" %} +[import:36-52, lang:"python"](../code/python/2d_convolution.py) {% endmethod %} With that, I believe we are at a good place to stop discussions on two-dimensional convolutions. @@ -148,6 +154,8 @@ We have also added code to create the Gaussian kernel and Sobel operator and app {% method %} {% sample lang="jl" %} [import, lang:"julia"](../code/julia/2d_convolution.jl) +{% sample lang="py" %} +[import, lang:"python"](../code/python/2d_convolution.py) {% endmethod %} @@ -54,6 +63,11 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +##### Images/Graphics + +- The image "[Cyclic](../res/cyclic.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + + ##### Text The text of this chapter was written by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). From 46bf5a378ae875c56369cdaa8da7b93c4f0e7ce4 Mon Sep 17 00:00:00 2001 From: Ayman Lafaz Date: Sun, 10 Oct 2021 15:15:43 +0100 Subject: [PATCH 040/146] added convolutional theorem implementation in python (#869) * added convolutional theorem implementation in python * fixed chapter linking * added comments to the code * changed random distribution to sawtooth * corrected previous commit * fixed comments Co-authored-by: James Schloss --- .../code/python/convolutional_theorem.py | 19 +++++++++++++++++++ .../convolutional_theorem.md | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 contents/convolutions/convolutional_theorem/code/python/convolutional_theorem.py diff --git a/contents/convolutions/convolutional_theorem/code/python/convolutional_theorem.py b/contents/convolutions/convolutional_theorem/code/python/convolutional_theorem.py new file mode 100644 index 000000000..f64f44a1d --- /dev/null +++ b/contents/convolutions/convolutional_theorem/code/python/convolutional_theorem.py @@ -0,0 +1,19 @@ +from scipy.fft import fft, ifft +import numpy as np + +# using the convolutional theorem +def convolve_fft(signal1, signal2): + return ifft(np.multiply(fft(signal1),fft(signal2))) + +# Sawtooth functions +x = [float(i)/200 for i in range(1,101)] +y = [float(i)/200 for i in range(1,101)] + +x /= np.linalg.norm(x) +y /= np.linalg.norm(y) + +# Convolving the two signals +fft_output = convolve_fft(x, y) + +np.savetxt("fft.dat", np.real(fft_output)) + diff --git a/contents/convolutions/convolutional_theorem/convolutional_theorem.md b/contents/convolutions/convolutional_theorem/convolutional_theorem.md index 7aa5c3fdf..1034f2018 100644 --- a/contents/convolutions/convolutional_theorem/convolutional_theorem.md +++ b/contents/convolutions/convolutional_theorem/convolutional_theorem.md @@ -44,6 +44,8 @@ For this example code, we will be using two sawtooth functions as we did in the {% method %} {% sample lang="jl" %} [import, lang:"julia"](code/julia/convolutional_theorem.jl) +{% sample lang="py" %} +[import, lang:"python"](code/python/convolutional_theorem.py) {% endmethod %} This should produce the following output: @@ -52,7 +54,6 @@ This should produce the following output:

- From 39f8c1c11b9066aa8b5a156f17c47979381490ce Mon Sep 17 00:00:00 2001 From: stormofice <58337328+stormofice@users.noreply.github.com> Date: Sun, 10 Oct 2021 16:28:38 +0200 Subject: [PATCH 041/146] Use `[#]\n` instead of `[#]` for human readable output (#873) --- contents/verlet_integration/code/asm-x64/verlet.s | 6 +++--- contents/verlet_integration/code/c++/verlet.cpp | 10 +++++----- contents/verlet_integration/code/c/verlet.c | 10 +++++----- .../verlet_integration/code/clisp/verlet.lisp | 10 +++++----- .../verlet_integration/code/fortran/verlet.f90 | 15 ++++++++++----- contents/verlet_integration/code/golang/verlet.go | 10 +++++----- .../verlet_integration/code/haskell/verlet.hs | 10 +++++----- contents/verlet_integration/code/java/Verlet.java | 10 +++++----- .../verlet_integration/code/javascript/verlet.js | 10 +++++----- contents/verlet_integration/code/julia/verlet.jl | 10 +++++----- contents/verlet_integration/code/kotlin/verlet.kt | 10 +++++----- contents/verlet_integration/code/nim/verlet.nim | 10 +++++----- contents/verlet_integration/code/python/verlet.py | 10 +++++----- contents/verlet_integration/code/ruby/verlet.rb | 10 +++++----- contents/verlet_integration/code/rust/verlet.rs | 10 +++++----- .../verlet_integration/code/swift/verlet.swift | 10 +++++----- 16 files changed, 83 insertions(+), 78 deletions(-) diff --git a/contents/verlet_integration/code/asm-x64/verlet.s b/contents/verlet_integration/code/asm-x64/verlet.s index 0e0d031b3..87de6cb7a 100644 --- a/contents/verlet_integration/code/asm-x64/verlet.s +++ b/contents/verlet_integration/code/asm-x64/verlet.s @@ -4,9 +4,9 @@ zero: .double 0.0 two: .double 2.0 half: .double 0.5 - verlet_fmt: .string "[#] Time for Verlet integration is:\n%lf\n" - stormer_fmt: .string "[#] Time for Stormer Verlet Integration is:\n%lf\n[#] Velocity for Stormer Verlet Integration is:\n%lf\n" - velocity_fmt: .string "[#] Time for Velocity Verlet Integration is:\n%lf\n[#] Velocity for Velocity Verlet Integration is:\n%lf\n" + verlet_fmt: .string "[#]\nTime for Verlet integration is:\n%lf\n" + stormer_fmt: .string "[#]\nTime for Stormer Verlet Integration is:\n%lf\n[#]\nVelocity for Stormer Verlet Integration is:\n%lf\n" + velocity_fmt: .string "[#]\nTime for Velocity Verlet Integration is:\n%lf\n[#]\nVelocity for Velocity Verlet Integration is:\n%lf\n" pos: .double 5.0 acc: .double -10.0 dt: .double 0.01 diff --git a/contents/verlet_integration/code/c++/verlet.cpp b/contents/verlet_integration/code/c++/verlet.cpp index 946ddc618..ccceb0ff3 100644 --- a/contents/verlet_integration/code/c++/verlet.cpp +++ b/contents/verlet_integration/code/c++/verlet.cpp @@ -64,19 +64,19 @@ int main() { // each of these functions. double time = verlet(5.0, -10, 0.01); - std::cout << "[#] Time for Verlet integration is:\n" \ + std::cout << "[#]\nTime for Verlet integration is:\n" \ << time << std::endl; timestep timestep_sv = stormer_verlet(5.0, -10, 0.01); - std::cout << "[#] Time for Stormer Verlet integration is:\n" \ + std::cout << "[#]\nTime for Stormer Verlet integration is:\n" \ << timestep_sv.time << std::endl; - std::cout << "[#] Velocity for Stormer Verlet integration is:\n" \ + std::cout << "[#]\nVelocity for Stormer Verlet integration is:\n" \ << timestep_sv.vel << std::endl; timestep timestep_vv = velocity_verlet(5.0, -10, 0.01); - std::cout << "[#] Time for velocity Verlet integration is:\n" \ + std::cout << "[#]\nTime for velocity Verlet integration is:\n" \ << timestep_vv.time << std::endl; - std::cout << "[#] Velocity for velocity Verlet integration is:\n" \ + std::cout << "[#]\nVelocity for velocity Verlet integration is:\n" \ << timestep_vv.vel << std::endl; return 0; diff --git a/contents/verlet_integration/code/c/verlet.c b/contents/verlet_integration/code/c/verlet.c index c42254974..a5febb92c 100644 --- a/contents/verlet_integration/code/c/verlet.c +++ b/contents/verlet_integration/code/c/verlet.c @@ -46,19 +46,19 @@ int main() { double time, vel; verlet(&time, 5.0, -10, 0.01); - printf("[#] Time for Verlet integration is:\n"); + printf("[#]\nTime for Verlet integration is:\n"); printf("%lf\n", time); stormer_verlet(&time, &vel, 5.0, -10, 0.01); - printf("[#] Time for Stormer Verlet integration is:\n"); + printf("[#]\nTime for Stormer Verlet integration is:\n"); printf("%lf\n", time); - printf("[#] Velocity for Stormer Verlet integration is:\n"); + printf("[#]\nVelocity for Stormer Verlet integration is:\n"); printf("%lf\n", vel); velocity_verlet(&time, &vel, 5.0, -10, 0.01); - printf("[#] Time for velocity Verlet integration is:\n"); + printf("[#]\nTime for velocity Verlet integration is:\n"); printf("%lf\n", time); - printf("[#] Velocity for Stormer Verlet integration is:\n"); + printf("[#]\nVelocity for Stormer Verlet integration is:\n"); printf("%lf\n", vel); return 0; diff --git a/contents/verlet_integration/code/clisp/verlet.lisp b/contents/verlet_integration/code/clisp/verlet.lisp index f08f2a7e6..f8d4c6c14 100644 --- a/contents/verlet_integration/code/clisp/verlet.lisp +++ b/contents/verlet_integration/code/clisp/verlet.lisp @@ -34,17 +34,17 @@ while (> p 0) finally (return (list time vel)))) -(format T "[#] Time for Verlet integration:~%") +(format T "[#]~%Time for Verlet integration:~%") (format T "~d~%" (verlet 5 -10 0.01)) (defvar stormer-verlet-result (stormer-verlet 5 -10 0.01)) -(format T "[#] Time for Stormer Verlet integration is:~%") +(format T "[#]~%Time for Stormer Verlet integration is:~%") (format T "~d~%" (first stormer-verlet-result)) -(format T "[#] Velocity for Stormer Verlet integration is:~%") +(format T "[#]~%Velocity for Stormer Verlet integration is:~%") (format T "~d~%" (second stormer-verlet-result)) (defvar velocity-verlet-result (velocity-verlet 5 -10 0.01)) -(format T "[#] Time for velocity Verlet integration is:~%") +(format T "[#]~%Time for velocity Verlet integration is:~%") (format T "~d~%" (first velocity-verlet-result)) -(format T "[#] Velocity for velocity Verlet integration is:~%") +(format T "[#]~%Velocity for velocity Verlet integration is:~%") (format T "~d~%" (second velocity-verlet-result)) \ No newline at end of file diff --git a/contents/verlet_integration/code/fortran/verlet.f90 b/contents/verlet_integration/code/fortran/verlet.f90 index 6999df1e5..3fda9f950 100644 --- a/contents/verlet_integration/code/fortran/verlet.f90 +++ b/contents/verlet_integration/code/fortran/verlet.f90 @@ -91,16 +91,19 @@ SUBROUTINE velocity_verlet(pos, acc, dt, time, vel) ! Verlet CALL verlet(pos, acc, dt, time) - WRITE(*,*) '[#] Time for Verlet integration:' + WRITE(*,*) '[#]' + WRITE(*,*) 'Time for Verlet integration:' WRITE(*,*) time ! stormer Verlet pos = 5d0 CALL stormer_verlet(pos, acc, dt, time, vel) - WRITE(*,*) '[#] Time for Stormer Verlet integration:' + WRITE(*,*) '[#]' + WRITE(*,*) 'Time for Stormer Verlet integration:' WRITE(*,*) time - WRITE(*,*) '[#] Velocity for Stormer Verlet integration:' + WRITE(*,*) '[#]' + WRITE(*,*) 'Velocity for Stormer Verlet integration:' WRITE(*,*) vel @@ -109,9 +112,11 @@ SUBROUTINE velocity_verlet(pos, acc, dt, time, vel) pos = 5d0 CALL velocity_verlet(pos, acc, dt, time, vel) - WRITE(*,*) '[#] Time for velocity Verlet integration:' + WRITE(*,*) '[#]' + WRITE(*,*) 'Time for velocity Verlet integration:' WRITE(*,*) time - WRITE(*,*) '[#] Velocity for velocity Verlet integration:' + WRITE(*,*) '[#]' + WRITE(*,*) 'Velocity for velocity Verlet integration:' WRITE(*,*) vel END PROGRAM verlet_integration diff --git a/contents/verlet_integration/code/golang/verlet.go b/contents/verlet_integration/code/golang/verlet.go index a7cd1c86b..d4fc956a9 100644 --- a/contents/verlet_integration/code/golang/verlet.go +++ b/contents/verlet_integration/code/golang/verlet.go @@ -43,18 +43,18 @@ func velocityVerlet(pos, acc, dt float64) (time, vel float64) { func main() { time := verlet(5., -10., .01) - fmt.Println("[#] Time for Verlet integration is:") + fmt.Println("[#]\nTime for Verlet integration is:") fmt.Println(time) time, vel := stormerVerlet(5., -10., .01) - fmt.Println("[#] Time for Stormer Verlet integration is:") + fmt.Println("[#]\nTime for Stormer Verlet integration is:") fmt.Println(time) - fmt.Println("[#] Velocity for Stormer Verlet integration is:") + fmt.Println("[#]\nVelocity for Stormer Verlet integration is:") fmt.Println(vel) time, vel = velocityVerlet(5., -10., .01) - fmt.Println("[#] Time for velocity Verlet integration is:") + fmt.Println("[#]\nTime for velocity Verlet integration is:") fmt.Println(time) - fmt.Println("[#] Velocity for velocity Verlet integration is:") + fmt.Println("[#]\nVelocity for velocity Verlet integration is:") fmt.Println(vel) } diff --git a/contents/verlet_integration/code/haskell/verlet.hs b/contents/verlet_integration/code/haskell/verlet.hs index 675c7f39b..af964d4d7 100644 --- a/contents/verlet_integration/code/haskell/verlet.hs +++ b/contents/verlet_integration/code/haskell/verlet.hs @@ -52,13 +52,13 @@ main = do let (_, v, _, t) = last $ takeWhile aboveGround $ trajectory m freefall dt p0 in (show t, show v) - putStrLn "[#] Time for Verlet integration is:" + putStrLn "[#]\nTime for Verlet integration is:" putStrLn $ fst $ timeVelocity verlet - putStrLn "[#] Time for Stormer Verlet integration is:" + putStrLn "[#]\nTime for Stormer Verlet integration is:" putStrLn $ fst $ timeVelocity stormerVerlet - putStrLn "[#] Velocity for Stormer Verlet integration is:" + putStrLn "[#]\nVelocity for Stormer Verlet integration is:" putStrLn $ snd $ timeVelocity stormerVerlet - putStrLn "[#] Time for velocity Verlet integration is:" + putStrLn "[#]\nTime for velocity Verlet integration is:" putStrLn $ fst $ timeVelocity velocityVerlet - putStrLn "[#] Velocity for velocity Verlet integration is:" + putStrLn "[#]\nVelocity for velocity Verlet integration is:" putStrLn $ snd $ timeVelocity velocityVerlet diff --git a/contents/verlet_integration/code/java/Verlet.java b/contents/verlet_integration/code/java/Verlet.java index 35387cf8b..38283abed 100644 --- a/contents/verlet_integration/code/java/Verlet.java +++ b/contents/verlet_integration/code/java/Verlet.java @@ -65,19 +65,19 @@ static VerletValues velocity_verlet(double pos, double acc, double dt) { public static void main(String[] args) { double verletTime = verlet(5.0, -10, 0.01); - System.out.println("[#] Time for Verlet integration is:"); + System.out.println("[#]\nTime for Verlet integration is:"); System.out.println(verletTime); VerletValues stormerVerlet = stormer_verlet(5.0, -10, 0.01); - System.out.println("[#] Time for Stormer Verlet integration is:"); + System.out.println("[#]\nTime for Stormer Verlet integration is:"); System.out.println(stormerVerlet.time); - System.out.println("[#] Velocity for Stormer Verlet integration is:"); + System.out.println("[#]\nVelocity for Stormer Verlet integration is:"); System.out.println(stormerVerlet.vel); VerletValues velocityVerlet = velocity_verlet(5.0, -10, 0.01); - System.out.println("[#] Time for velocity Verlet integration is:"); + System.out.println("[#]\nTime for velocity Verlet integration is:"); System.out.println(velocityVerlet.time); - System.out.println("[#] Velocity for velocity Verlet integration is:"); + System.out.println("[#]\nVelocity for velocity Verlet integration is:"); System.out.println(velocityVerlet.vel); } diff --git a/contents/verlet_integration/code/javascript/verlet.js b/contents/verlet_integration/code/javascript/verlet.js index 7ea09e187..d406482d4 100644 --- a/contents/verlet_integration/code/javascript/verlet.js +++ b/contents/verlet_integration/code/javascript/verlet.js @@ -45,17 +45,17 @@ function velocityVerlet(pos, acc, dt) { } const time = verlet(5, -10, 0.01); -console.log(`[#] Time for Verlet integration is:`); +console.log(`[#]\nTime for Verlet integration is:`); console.log(`${time}`); const stormer = stormerVerlet(5, -10, 0.01); -console.log(`[#] Time for Stormer Verlet integration is:`); +console.log(`[#]\nTime for Stormer Verlet integration is:`); console.log(`${stormer.time}`); -console.log(`[#] Velocity for Stormer Verlet integration is:`); +console.log(`[#]\nVelocity for Stormer Verlet integration is:`); console.log(`${stormer.vel}`); const velocity = velocityVerlet(5, -10, 0.01); -console.log(`[#] Time for velocity Verlet integration is:`); +console.log(`[#]\nTime for velocity Verlet integration is:`); console.log(`${velocity.time}`); -console.log(`[#] Velocity for velocity Verlet integration is:`); +console.log(`[#]\nVelocity for velocity Verlet integration is:`); console.log(`${velocity.vel}`); diff --git a/contents/verlet_integration/code/julia/verlet.jl b/contents/verlet_integration/code/julia/verlet.jl index b9edcea98..2d50e5512 100644 --- a/contents/verlet_integration/code/julia/verlet.jl +++ b/contents/verlet_integration/code/julia/verlet.jl @@ -46,19 +46,19 @@ end function main() time = verlet(5.0, -10.0, 0.01); - println("[#] Time for Verlet integration is:") + println("[#]\nTime for Verlet integration is:") println("$(time)") time, vel = stormer_verlet(5.0, -10.0, 0.01); - println("[#] Time for Stormer Verlet integration is:") + println("[#]\nTime for Stormer Verlet integration is:") println("$(time)") - println("[#] Velocity for Stormer Verlet integration is:") + println("[#]\nVelocity for Stormer Verlet integration is:") println("$(vel)") time, vel = velocity_verlet(5.0, -10.0, 0.01); - println("[#] Time for velocity Verlet integration is:") + println("[#]\nTime for velocity Verlet integration is:") println("$(time)") - println("[#] Velocity for velocity Verlet integration is:") + println("[#]\nVelocity for velocity Verlet integration is:") println("$(vel)") end diff --git a/contents/verlet_integration/code/kotlin/verlet.kt b/contents/verlet_integration/code/kotlin/verlet.kt index 79bee7b6a..3b365451c 100644 --- a/contents/verlet_integration/code/kotlin/verlet.kt +++ b/contents/verlet_integration/code/kotlin/verlet.kt @@ -43,18 +43,18 @@ fun velocityVerlet(_pos: Double, acc: Double, dt: Double): VerletValues { fun main(args: Array) { val verletTime = verlet(5.0, -10.0, 0.01) - println("[#] Time for Verlet integration is:") + println("[#]\nTime for Verlet integration is:") println("$verletTime") val stormerVerlet = stormerVerlet(5.0, -10.0, 0.01) - println("[#] Time for Stormer Verlet integration is:") + println("[#]\nTime for Stormer Verlet integration is:") println("${stormerVerlet.time}") - println("[#] Velocity for Stormer Verlet integration is:") + println("[#]\nVelocity for Stormer Verlet integration is:") println("${stormerVerlet.vel}") val velocityVerlet = velocityVerlet(5.0, -10.0, 0.01) - println("[#] Time for Velocity Verlet integration is:") + println("[#]\nTime for Velocity Verlet integration is:") println("${velocityVerlet.time}") - println("[#] Velocity for Velocity Verlet integration is:") + println("[#]\nVelocity for Velocity Verlet integration is:") println("${velocityVerlet.vel}") } diff --git a/contents/verlet_integration/code/nim/verlet.nim b/contents/verlet_integration/code/nim/verlet.nim index 2e92b57c4..ff454b7ee 100644 --- a/contents/verlet_integration/code/nim/verlet.nim +++ b/contents/verlet_integration/code/nim/verlet.nim @@ -46,17 +46,17 @@ func velocityVerlet(pos_in, acc, dt: float): (float, float) = when isMainModule: let timeV = verlet(5.0, -10.0, 0.01) - echo "[#] Time for Verlet integration is:" + echo "[#]\nTime for Verlet integration is:" echo timeV let (timeSV, velSV) = stormerVerlet(5.0, -10.0, 0.01) - echo "[#] Time for Stormer Verlet integration is:" + echo "[#]\nTime for Stormer Verlet integration is:" echo timeSV - echo "[#] Velocity for Stormer Verlet integration is:" + echo "[#]\nVelocity for Stormer Verlet integration is:" echo velSV let (timeVV, velVV) = velocityVerlet(5.0, -10.0, 0.01) - echo "[#] Time for velocity Verlet integration is:" + echo "[#]\nTime for velocity Verlet integration is:" echo timeVV - echo "[#] Velocity for velocity Verlet integration is:" + echo "[#]\nVelocity for velocity Verlet integration is:" echo velVV diff --git a/contents/verlet_integration/code/python/verlet.py b/contents/verlet_integration/code/python/verlet.py index 18dc627d3..063e19666 100644 --- a/contents/verlet_integration/code/python/verlet.py +++ b/contents/verlet_integration/code/python/verlet.py @@ -35,19 +35,19 @@ def velocity_verlet(pos, acc, dt): def main(): time = verlet(5, -10, 0.01) - print("[#] Time for Verlet integration is:") + print("[#]\nTime for Verlet integration is:") print("{:.10f}".format(time)) time, vel = stormer_verlet(5, -10, 0.01) - print("[#] Time for Stormer Verlet integration is:") + print("[#]\nTime for Stormer Verlet integration is:") print("{:.10f}".format(time)) - print("[#] Velocity for Stormer Verlet integration is:") + print("[#]\nVelocity for Stormer Verlet integration is:") print("{:.10f}".format(vel)) time, vel = velocity_verlet(5, -10, 0.01) - print("[#] Time for velocity Verlet integration is:") + print("[#]\nTime for velocity Verlet integration is:") print("{:.10f}".format(time)) - print("[#] Velocity for velocity Verlet integration is:") + print("[#]\nVelocity for velocity Verlet integration is:") print("{:.10f}".format(vel)) diff --git a/contents/verlet_integration/code/ruby/verlet.rb b/contents/verlet_integration/code/ruby/verlet.rb index 4a6c38a48..d11243568 100644 --- a/contents/verlet_integration/code/ruby/verlet.rb +++ b/contents/verlet_integration/code/ruby/verlet.rb @@ -45,17 +45,17 @@ def velocity_verlet(pos, acc, dt) end -puts "[#] Time for Verlet integration is:" +puts "[#]\nTime for Verlet integration is:" p verlet(5.0, -10, 0.01) time, vel = stormer_verlet(5.0, -10, 0.01) -puts "[#] Time for Stormer Verlet integration is:" +puts "[#]\nTime for Stormer Verlet integration is:" p time -puts "[#] Velocity for Stormer Verlet integration is:" +puts "[#]\nVelocity for Stormer Verlet integration is:" p vel time, vel = velocity_verlet(5.0, -10, 0.01) -puts "[#] Time for velocity Verlet integration is:" +puts "[#]\nTime for velocity Verlet integration is:" p time -puts "[#] Velocity for velocity Verlet integration is:" +puts "[#]\nVelocity for velocity Verlet integration is:" p vel diff --git a/contents/verlet_integration/code/rust/verlet.rs b/contents/verlet_integration/code/rust/verlet.rs index f765da864..8901a3790 100644 --- a/contents/verlet_integration/code/rust/verlet.rs +++ b/contents/verlet_integration/code/rust/verlet.rs @@ -49,16 +49,16 @@ fn main() { let (time_sv, vel_sv) = stormer_verlet(5.0, -10.0, 0.01); let (time_vv, vel_vv) = velocity_verlet(5.0, -10.0, 0.01); - println!("[#] Time for Verlet integration is:"); + println!("[#]\nTime for Verlet integration is:"); println!("{}", time_v); - println!("[#] Time for Stormer Verlet integration is:"); + println!("[#]\nTime for Stormer Verlet integration is:"); println!("{}", time_sv); - println!("[#] Velocity for Stormer Verlet integration is:"); + println!("[#]\nVelocity for Stormer Verlet integration is:"); println!("{}", vel_sv); - println!("[#] Time for velocity Verlet integration is:"); + println!("[#]\nTime for velocity Verlet integration is:"); println!("{}", time_vv); - println!("[#] Velocity for velocity Verlet integration is:"); + println!("[#]\nVelocity for velocity Verlet integration is:"); println!("{}", vel_vv); } diff --git a/contents/verlet_integration/code/swift/verlet.swift b/contents/verlet_integration/code/swift/verlet.swift index 7991a0082..f7d1973bc 100644 --- a/contents/verlet_integration/code/swift/verlet.swift +++ b/contents/verlet_integration/code/swift/verlet.swift @@ -50,19 +50,19 @@ func velocityVerlet(pos: Double, acc: Double, dt: Double) -> (time: Double, vel: func main() { let verletTime = verlet(pos: 5.0, acc: -10.0, dt: 0.01) - print("[#] Time for Verlet integration is:") + print("[#]\nTime for Verlet integration is:") print("\(verletTime)") let stormer = stormerVerlet(pos: 5.0, acc: -10.0, dt: 0.01); - print("[#] Time for Stormer Verlet integration is:") + print("[#]\nTime for Stormer Verlet integration is:") print("\(stormer.time)") - print("[#] Velocity for Stormer Verlet integration is:") + print("[#]\nVelocity for Stormer Verlet integration is:") print("\(stormer.vel)") let velVerlet = velocityVerlet(pos: 5.0, acc: -10, dt: 0.01) - print("[#] Time for velocity Verlet integration is:") + print("[#]\nTime for velocity Verlet integration is:") print("\(velVerlet.time)") - print("[#] Velocity for velocity Verlet integration is:") + print("[#]\nVelocity for velocity Verlet integration is:") print("\(velVerlet.vel)") } From f3bd8f44ac6010b78e19dc2061b8bd3ba4ec10ca Mon Sep 17 00:00:00 2001 From: Mahdi <24981501+mahdisarikhani@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:03:55 +0330 Subject: [PATCH 042/146] Add approximate counting algorithm in C (#844) * Add approximate counting algorithm in C * Fix typo Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: James Schloss --- .../approximate_counting.md | 2 + .../code/c/approximate_counting.c | 82 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 contents/approximate_counting/code/c/approximate_counting.c diff --git a/contents/approximate_counting/approximate_counting.md b/contents/approximate_counting/approximate_counting.md index f63d7db43..654721844 100644 --- a/contents/approximate_counting/approximate_counting.md +++ b/contents/approximate_counting/approximate_counting.md @@ -360,6 +360,8 @@ As we do not have any objects to count, we will instead simulate the counting wi {% method %} {% sample lang="jl" %} [import, lang:"julia"](code/julia/approximate_counting.jl) +{% sample lang="c" %} +[import, lang:"c"](code/c/approximate_counting.c) {% sample lang="cpp" %} [import, lang:"cpp"](code/c++/approximate_counting.cpp) {% sample lang="python" %} diff --git a/contents/approximate_counting/code/c/approximate_counting.c b/contents/approximate_counting/code/c/approximate_counting.c new file mode 100644 index 000000000..ded7a518e --- /dev/null +++ b/contents/approximate_counting/code/c/approximate_counting.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +// This function returns a pseudo-random number between 0 and 1 +double drand() +{ + return (double)rand() / RAND_MAX; +} + +// This function takes +// - v: value in register +// - a: a scaling value for the logarithm based on Morris's paper +// It returns the approximate count +double n(double v, double a) +{ + return a * (pow(1 + 1 / a, v) - 1); +} + +// This function takes +// - v: value in register +// - a: a scaling value for the logarithm based on Morris's paper +// It returns a new value for v +double increment(double v, double a) +{ + // delta is the probability of incrementing our counter + double delta = 1 / (n(v + 1, a) - n(v, a)); + + if (drand() <= delta) { + return v + 1; + } + return v; +} + +// This function simulates counting and takes +// - n_items: number of items to count and loop over +// - a: a scaling value for the logarithm based on Morris's paper +// It returns n(v, a), the approximate count +double approximate_count(size_t n_items, double a) +{ + int v = 0; + for (size_t i = 0; i < n_items; ++i) { + v = increment(v, a); + } + + return n(v, a); +} + +// This function takes +// - n_trials: the number of counting trials +// - n_items: the number off items to count +// - a: a scaling value for the logarithm based on Morris's paper +// - threshold: the maximum percent error allowed +// It terminates the program on failure +void test_approximation_count(size_t n_trials, size_t n_items, double a, + double threshold) +{ + double sum = 0.0; + for (size_t i = 0; i < n_trials; ++i) { + sum += approximate_count(n_items, a); + } + double avg = sum / n_trials; + + assert(fabs((avg - n_items) / n_items) < threshold); +} + +int main() +{ + srand(time(NULL)); + + printf("Counting Tests, 100 trials\n"); + printf("testing 1000, a = 30, 1%% error\n"); + test_approximation_count(100, 1000, 30, 0.1); + printf("testing 12345, a = 10, 1%% error\n"); + test_approximation_count(100, 12345, 10, 0.1); + printf("testing 222222, a = 0.5, 10%% error\n"); + test_approximation_count(100, 222222, 0.5, 0.2); + + return 0; +} From d81942cd9c8060421cdb721f3745bf187531721f Mon Sep 17 00:00:00 2001 From: Ayman Lafaz Date: Tue, 12 Oct 2021 12:12:10 +0100 Subject: [PATCH 043/146] added 1d convolution implementation in python (#874) * added 1d convolution implementation in python * fixed some mistakes in the code so it outputs correct results * making the code look better * spacing code properly for readability --- contents/convolutions/1d/1d.md | 14 +++++ .../1d/code/python/1d_convolution.py | 53 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 contents/convolutions/1d/code/python/1d_convolution.py diff --git a/contents/convolutions/1d/1d.md b/contents/convolutions/1d/1d.md index d5d77652b..e3f9a3770 100644 --- a/contents/convolutions/1d/1d.md +++ b/contents/convolutions/1d/1d.md @@ -56,6 +56,8 @@ With this in mind, we can almost directly transcribe the discrete equation into [import:27-46, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:63-84, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:18-27, lang:"python"](code/python/1d_convolution.py) {% endmethod %} The easiest way to reason about this code is to read it as you might read a textbook. @@ -189,6 +191,8 @@ Here it is again for clarity: [import:27-46, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:63-84, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:18-27, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Here, the main difference between the bounded and unbounded versions is that the output array size is smaller in the bounded case. @@ -199,6 +203,8 @@ For an unbounded convolution, the function would be called with a the output arr [import:58-59, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:96-97, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:37-38, lang:"python"](code/python/1d_convolution.py) {% endmethod %} On the other hand, the bounded call would set the output array size to simply be the length of the signal @@ -208,6 +214,8 @@ On the other hand, the bounded call would set the output array size to simply be [import:61-62, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:98-99, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:40-41, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Finally, as we mentioned before, it is possible to center bounded convolutions by changing the location where we calculate the each point along the filter. @@ -218,6 +226,8 @@ This can be done by modifying the following line: [import:35-35, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:71-71, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:22-22, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Here, `j` counts from `i-length(filter)` to `i`. @@ -252,6 +262,8 @@ In code, this typically amounts to using some form of modulus operation, as show [import:4-25, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import:38-61, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import:5-15, lang:"python"](code/python/1d_convolution.py) {% endmethod %} This is essentially the same as before, except for the modulus operations, which allow us to work on a periodic domain. @@ -269,6 +281,8 @@ For the code associated with this chapter, we have used the convolution to gener [import, lang:"julia"](code/julia/1d_convolution.jl) {% sample lang="cs" %} [import, lang:"csharp"](code/csharp/1DConvolution.cs) +{% sample lang="py" %} +[import, lang:"python"](code/python/1d_convolution.py) {% endmethod %} At a test case, we have chosen to use two sawtooth functions, which should produce the following images: diff --git a/contents/convolutions/1d/code/python/1d_convolution.py b/contents/convolutions/1d/code/python/1d_convolution.py new file mode 100644 index 000000000..e77e68d09 --- /dev/null +++ b/contents/convolutions/1d/code/python/1d_convolution.py @@ -0,0 +1,53 @@ +import numpy as np + +def mod1(x, y): return ((x % y) + y) % y + +def convolve_cyclic(signal, filter_array): + output_size = max(len(signal), len(filter_array)) + out = np.zeros(output_size) + s = 0 + + for i in range(output_size): + for j in range(output_size): + if(mod1(i - j, output_size) < len(filter_array)): + s += signal[mod1(j - 1, output_size)] * filter_array[mod1(i - j, output_size)] + out[i] = s + s = 0 + + return out + + +def convolve_linear(signal, filter_array, output_size): + out = np.zeros(output_size) + s = 0 + + for i in range(output_size): + for j in range(max(0, i - len(filter_array)), i + 1): + if j < len(signal) and (i - j) < len(filter_array): + s += signal[j] * filter_array[i - j] + out[i] = s + s = 0 + + return out + +# sawtooth functions for x and y +x = [float(i + 1)/200 for i in range(200)] +y = [float(i + 1)/200 for i in range(200)] + +# Normalization is not strictly necessary, but good practice +x /= np.linalg.norm(x) +y /= np.linalg.norm(y) + +# full convolution, output will be the size of x + y - 1 +full_linear_output = convolve_linear(x, y, len(x) + len(y) - 1) + +# simple boundaries +simple_linear_output = convolve_linear(x, y, len(x)) + +# cyclic convolution +cyclic_output = convolve_cyclic(x, y) + +# outputting convolutions to different files for plotting in external code +np.savetxt('full_linear.dat', full_linear_output) +np.savetxt('simple_linear.dat', simple_linear_output) +np.savetxt('cyclic.dat', cyclic_output) From bfc180dcf353b43ed34b4b0e3ba21d8d4eb927c8 Mon Sep 17 00:00:00 2001 From: Ayman Lafaz Date: Tue, 12 Oct 2021 15:20:56 +0100 Subject: [PATCH 044/146] fixing 1d convolution markdown file (#879) --- contents/convolutions/1d/1d.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contents/convolutions/1d/1d.md b/contents/convolutions/1d/1d.md index e3f9a3770..9a2e652d1 100644 --- a/contents/convolutions/1d/1d.md +++ b/contents/convolutions/1d/1d.md @@ -57,7 +57,7 @@ With this in mind, we can almost directly transcribe the discrete equation into {% sample lang="cs" %} [import:63-84, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:18-27, lang:"python"](code/python/1d_convolution.py) +[import:20-31, lang:"python"](code/python/1d_convolution.py) {% endmethod %} The easiest way to reason about this code is to read it as you might read a textbook. @@ -192,7 +192,7 @@ Here it is again for clarity: {% sample lang="cs" %} [import:63-84, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:18-27, lang:"python"](code/python/1d_convolution.py) +[import:20-31, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Here, the main difference between the bounded and unbounded versions is that the output array size is smaller in the bounded case. @@ -204,7 +204,7 @@ For an unbounded convolution, the function would be called with a the output arr {% sample lang="cs" %} [import:96-97, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:37-38, lang:"python"](code/python/1d_convolution.py) +[import:41-42, lang:"python"](code/python/1d_convolution.py) {% endmethod %} On the other hand, the bounded call would set the output array size to simply be the length of the signal @@ -215,7 +215,7 @@ On the other hand, the bounded call would set the output array size to simply be {% sample lang="cs" %} [import:98-99, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:40-41, lang:"python"](code/python/1d_convolution.py) +[import:44-45, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Finally, as we mentioned before, it is possible to center bounded convolutions by changing the location where we calculate the each point along the filter. @@ -227,7 +227,7 @@ This can be done by modifying the following line: {% sample lang="cs" %} [import:71-71, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:22-22, lang:"python"](code/python/1d_convolution.py) +[import:25-25, lang:"python"](code/python/1d_convolution.py) {% endmethod %} Here, `j` counts from `i-length(filter)` to `i`. @@ -263,7 +263,7 @@ In code, this typically amounts to using some form of modulus operation, as show {% sample lang="cs" %} [import:38-61, lang:"csharp"](code/csharp/1DConvolution.cs) {% sample lang="py" %} -[import:5-15, lang:"python"](code/python/1d_convolution.py) +[import:5-17, lang:"python"](code/python/1d_convolution.py) {% endmethod %} This is essentially the same as before, except for the modulus operations, which allow us to work on a periodic domain. From 1c820498272a6d97b2418925ac939f5b66528f8b Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Fri, 15 Oct 2021 21:32:35 +0200 Subject: [PATCH 045/146] Add racket setup to devcontainer (#875) --- .devcontainer/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e014b404b..a7bda0bd3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -73,7 +73,8 @@ RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D6 RUN sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/' # Setup Racket -## Use: https://ubunlog.com/en/racket-install-ubuntu-programming-language +RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D9D33FCD84D82C17288BA03B3C9A6980F827E01E +RUN sudo add-apt-repository 'deb http://ppa.launchpad.net/plt/racket/ubuntu focal main' # Setup Scheme ## Use: https://github.com/ashinn/chibi-scheme @@ -99,7 +100,7 @@ RUN sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu fo # Install the packages that needed extra help RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base + && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket RUN pip install wheel matplotlib numpy coconut From c206831d9c9b75c7019e27bb9bc5a95c66162c8a Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sat, 16 Oct 2021 19:01:30 +0200 Subject: [PATCH 046/146] Normalize inputs for scheme euclid algorithm (#878) Change inputs to make it consistent with other examples. --- contents/euclidean_algorithm/code/scheme/euclidalg.ss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contents/euclidean_algorithm/code/scheme/euclidalg.ss b/contents/euclidean_algorithm/code/scheme/euclidalg.ss index 3d891ba73..959ebdeca 100644 --- a/contents/euclidean_algorithm/code/scheme/euclidalg.ss +++ b/contents/euclidean_algorithm/code/scheme/euclidalg.ss @@ -12,4 +12,5 @@ (euclid-mod b (modulo a b)))) (display (euclid-mod (* 64 67) (* 64 81))) (newline) -(display (euclid-sub (* 64 12) (* 64 27))) (newline) +(display (euclid-sub (* 128 12) (* 128 77))) (newline) + From a86911467345d938497c527471deed5808a811ff Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sat, 16 Oct 2021 19:14:44 +0200 Subject: [PATCH 047/146] Add initial setup for Swift in devcontainer (#880) --- .devcontainer/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a7bda0bd3..8cb8c2ab7 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -83,7 +83,9 @@ RUN sudo add-apt-repository 'deb http://ppa.launchpad.net/plt/racket/ubuntu foca ## using 1.x right now.... in future checkout snap or adobe air? # Setup Swift -## ? +RUN mkdir -p ~/swift && wget https://swift.org/builds/swift-5.5-release/ubuntu2004/swift-5.5-RELEASE/swift-5.5-RELEASE-ubuntu20.04.tar.gz -O ~/swift/swift.tar.gz && \ + tar -xzf ~/swift/swift.tar.gz -C ~/swift --strip-components=1 +ENV PATH=$PATH:~/swift/usr/bin # Setup viml ## ? From cee127059873340b68d7a653ed2f1943e3e9cc85 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sat, 16 Oct 2021 19:15:51 +0200 Subject: [PATCH 048/146] Add scheme setup to devcontainer (#876) --- .devcontainer/Dockerfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 8cb8c2ab7..bc58ae358 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -72,13 +72,11 @@ ENV PATH=$PATH:/root/factor/factor RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 RUN sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/' -# Setup Racket +# Setup Racket and Scheme +# To run scheme files, use `racket -f ` RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D9D33FCD84D82C17288BA03B3C9A6980F827E01E RUN sudo add-apt-repository 'deb http://ppa.launchpad.net/plt/racket/ubuntu focal main' -# Setup Scheme -## Use: https://github.com/ashinn/chibi-scheme - # Setup Scratch ## using 1.x right now.... in future checkout snap or adobe air? From d631070d310132f996bc52caebadeec0a7990104 Mon Sep 17 00:00:00 2001 From: Eric Berquist Date: Mon, 18 Oct 2021 13:52:46 +0000 Subject: [PATCH 049/146] Clean up Monte Carlo integration in Racket (#781) * Clean up Monte Carlo integration in Racket * Add blank lines in Monte Carlo integration in Clojure * Change Racket lang include from lisp to racket --- .../code/clojure/monte_carlo.clj | 5 ++- .../code/racket/monte_carlo.rkt | 39 ++++++++++--------- .../monte_carlo_integration.md | 4 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/contents/monte_carlo_integration/code/clojure/monte_carlo.clj b/contents/monte_carlo_integration/code/clojure/monte_carlo.clj index f66baef67..de517e56c 100644 --- a/contents/monte_carlo_integration/code/clojure/monte_carlo.clj +++ b/contents/monte_carlo_integration/code/clojure/monte_carlo.clj @@ -8,9 +8,11 @@ (map #(* % %)) (reduce +)) (* r r))) + (defn rand-point [r] "return a random point from (0,0) inclusive to (r,r) exclusive" (repeatedly 2 #(rand r))) + (defn monte-carlo [n r] "take the number of random points and radius return an estimate to pi" @@ -22,11 +24,12 @@ pi" (if (in-circle? (rand-point r) r) (inc count) count)))))) + (defn -main [] (let [constant-pi Math/PI computed-pi (monte-carlo 10000000 2) ;; this may take some time on lower end machines difference (Math/abs (- constant-pi computed-pi)) error (* 100 (/ difference constant-pi))] (println "world's PI: " constant-pi - ",our PI: " (double computed-pi) + ",our PI: " (double computed-pi) ",error: " error))) diff --git a/contents/monte_carlo_integration/code/racket/monte_carlo.rkt b/contents/monte_carlo_integration/code/racket/monte_carlo.rkt index 0f652db93..0278e7ed6 100755 --- a/contents/monte_carlo_integration/code/racket/monte_carlo.rkt +++ b/contents/monte_carlo_integration/code/racket/monte_carlo.rkt @@ -1,22 +1,25 @@ -#lang racket -(define (in_circle x y) - (< (+ (sqr x) (sqr y)) 1) - ) +#lang racket/base -(define (monte_carlo_pi n) - (* (/ (local ((define (monte_carlo* n count) +(require racket/local) +(require racket/math) + +(define (in-circle x y) + "Checks if a point is in a unit circle" + (< (+ (sqr x) (sqr y)) 1)) + +(define (monte-carlo-pi n) + "Returns an approximation of pi" + (* (/ (local ((define (monte-carlo-pi* n count) (if (= n 0) count - (monte_carlo_pi* (sub1 n) - (if (in_circle (random) (random)) - (add1 count) - count - ) - ) - ) - )) (monte_carlo_pi* n 0) - ) n) 4) - ) - + (monte-carlo-pi* (sub1 n) + (if (in-circle (random) (random)) + (add1 count) + count))))) + (monte-carlo-pi* n 0)) n) 4)) -(display (monte_carlo_pi 1000)) +(define nsamples 5000000) +(define pi-estimate (monte-carlo-pi nsamples)) +(displayln (string-append "Estimate (rational): " (number->string pi-estimate))) +(displayln (string-append "Estimate (float): " (number->string (real->single-flonum pi-estimate)))) +(displayln (string-append "Error:" (number->string (* (/ (abs (- pi-estimate pi)) pi) 100)))) diff --git a/contents/monte_carlo_integration/monte_carlo_integration.md b/contents/monte_carlo_integration/monte_carlo_integration.md index ac6895404..cf5640ffa 100644 --- a/contents/monte_carlo_integration/monte_carlo_integration.md +++ b/contents/monte_carlo_integration/monte_carlo_integration.md @@ -80,7 +80,7 @@ each point is tested to see whether it's in the circle or not: {% sample lang="lua" %} [import:2-4, lang="lua"](code/lua/monte_carlo.lua) {% sample lang="racket" %} -[import:2-4, lang:"lisp"](code/racket/monte_carlo.rkt) +[import:6-8, lang:"racket"](code/racket/monte_carlo.rkt) {% sample lang="scala" %} [import:3-3, lang:"scala"](code/scala/monte_carlo.scala) {% sample lang="lisp" %} @@ -188,7 +188,7 @@ Feel free to submit your version via pull request, and thanks for reading! {% sample lang="lua" %} [import, lang="lua"](code/lua/monte_carlo.lua) {% sample lang="racket" %} -[import, lang:"lisp"](code/racket/monte_carlo.rkt) +[import, lang:"racket"](code/racket/monte_carlo.rkt) {% sample lang="scala" %} [import, lang:"scala"](code/scala/monte_carlo.scala) {% sample lang="lisp" %} From 7f814fa755734a92bbe299f56e69be4ba4148056 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 18 Oct 2021 17:44:55 +0200 Subject: [PATCH 050/146] Add C++ code for Flood Fill algorithm (#860) --- CONTRIBUTORS.md | 1 + contents/flood_fill/code/cpp/flood_fill.cpp | 156 ++++++++++++++++++++ contents/flood_fill/flood_fill.md | 10 ++ 3 files changed, 167 insertions(+) create mode 100644 contents/flood_fill/code/cpp/flood_fill.cpp diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index fb8ecde19..e3707e290 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -59,3 +59,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Mahdi Sarikhani - Ridham177 - Hugo Salou +- Dimitri Belopopsky diff --git a/contents/flood_fill/code/cpp/flood_fill.cpp b/contents/flood_fill/code/cpp/flood_fill.cpp new file mode 100644 index 000000000..918566809 --- /dev/null +++ b/contents/flood_fill/code/cpp/flood_fill.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include + +using CartesianIndex = std::array; + +auto inbounds(CartesianIndex size, CartesianIndex loc) { + if (loc[0] < 0 || loc[1] < 0) { + return false; + } else if (loc[0] >= size[0] || loc[1] >= size[1]) { + return false; + } + return true; +} + +auto find_neighbors( + std::vector> const& grid, + CartesianIndex loc, + float old_value, + float /* new_value */) { + + const std::vector possible_neighbors{ + {loc[0], loc[1] + 1}, + {loc[0] + 1, loc[1]}, + {loc[0], loc[1] - 1}, + {loc[0] - 1, loc[1]}}; + + std::vector neighbors; + + for (auto const& possible_neighbor : possible_neighbors) { + const auto size = CartesianIndex{ + static_cast(grid[0].size()), static_cast(grid.size())}; + const auto x = static_cast(possible_neighbor[0]); + const auto y = static_cast(possible_neighbor[1]); + if (inbounds(size, possible_neighbor) && grid[x][y] == old_value) { + neighbors.push_back(possible_neighbor); + } + } + + return neighbors; +} + +void recursive_fill( + std::vector>& grid, + CartesianIndex loc, + float old_value, + float new_value) { + if (old_value == new_value) { + return; + } + + const auto x = static_cast(loc[0]); + const auto y = static_cast(loc[1]); + + grid[x][y] = new_value; + + const auto possible_neighbors = find_neighbors(grid, loc, old_value, new_value); + for (auto const& possible_neighbor : possible_neighbors) { + recursive_fill(grid, possible_neighbor, old_value, new_value); + } +} + +void queue_fill( + std::vector>& grid, + CartesianIndex loc, + float old_value, + float new_value) { + if (old_value == new_value) { + return; + } + + auto q = std::queue{}; + q.push(loc); + const auto x = static_cast(loc[0]); + const auto y = static_cast(loc[1]); + grid[x][y] = new_value; + + while (q.size() > 0) { + const auto current_loc = q.front(); + q.pop(); + const auto possible_neighbors = + find_neighbors(grid, current_loc, old_value, new_value); + for (auto const& neighbor : possible_neighbors) { + const auto neighbor_x = static_cast(neighbor[0]); + const auto neighbor_y = static_cast(neighbor[1]); + grid[neighbor_x][neighbor_y] = new_value; + q.push(neighbor); + } + } +} + +void stack_fill( + std::vector>& grid, + CartesianIndex loc, + float old_value, + float new_value) { + if (old_value == new_value) { + return; + } + + auto s = std::stack{}; + s.push(loc); + + while (s.size() > 0) { + const auto current_loc = s.top(); + s.pop(); + + const auto x = static_cast(current_loc[0]); + const auto y = static_cast(current_loc[1]); + + if (grid[x][y] == old_value) { + grid[x][y] = new_value; + const auto possible_neighbors = + find_neighbors(grid, current_loc, old_value, new_value); + for (auto const& neighbor : possible_neighbors) { + s.push(neighbor); + } + } + } +} + +int main() { + + const std::vector> grid{ + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}, + {0, 0, 1, 0, 0}}; + + const std::vector> solution_grid{ + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 0}, + {1, 1, 1, 0, 0}}; + + const CartesianIndex start_loc{1, 1}; + + auto test_grid = grid; + recursive_fill(test_grid, start_loc, 0.0, 1.0); + assert(test_grid == solution_grid); + + test_grid = grid; + queue_fill(test_grid, start_loc, 0.0, 1.0); + assert(test_grid == solution_grid); + + test_grid = grid; + stack_fill(test_grid, start_loc, 0.0, 1.0); + assert(test_grid == solution_grid); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/contents/flood_fill/flood_fill.md b/contents/flood_fill/flood_fill.md index 185050fe1..4c7e5936e 100644 --- a/contents/flood_fill/flood_fill.md +++ b/contents/flood_fill/flood_fill.md @@ -90,6 +90,8 @@ In code, this might look like this: [import:23-41, lang:"julia"](code/julia/flood_fill.jl) {% sample lang="c" %} [import:28-46, lang:"c"](code/c/flood_fill.c) +{% sample lang="cpp" %} +[import:19-44, lang:"cpp"](code/cpp/flood_fill.cpp) {% sample lang="py" %} [import:10-25, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} @@ -110,6 +112,8 @@ In code, it might look like this: [import:92-104, lang:"julia"](code/julia/flood_fill.jl) {% sample lang="c" %} [import:174-189, lang:"c"](code/c/flood_fill.c) +{% sample lang="cpp" %} +[import:46-64, lang:"cpp"](code/cpp/flood_fill.cpp) {% sample lang="py" %} [import:55-63, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} @@ -125,6 +129,8 @@ Additionally, it is possible to do the same type of traversal by managing a stac [import:43-63, lang:"julia"](code/julia/flood_fill.jl) {% sample lang="c" %} [import:79-102, lang:"c"](code/c/flood_fill.c) +{% sample lang="cpp" %} +[import:95-123, lang:"cpp"](code/cpp/flood_fill.cpp) {% sample lang="py" %} [import:27-36, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} @@ -168,6 +174,8 @@ The code would look something like this: [import:66-90, lang:"julia"](code/julia/flood_fill.jl) {% sample lang="c" %} [import:149-172, lang:"c"](code/c/flood_fill.c) +{% sample lang="cpp" %} +[import:66-93, lang:"cpp"](code/cpp/flood_fill.cpp) {% sample lang="py" %} [import:38-53, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} @@ -250,6 +258,8 @@ After, we will fill in the left-hand side of the array to be all ones by choosin [import, lang:"julia"](code/julia/flood_fill.jl) {% sample lang="c" %} [import, lang:"c"](code/c/flood_fill.c) +{% sample lang="cpp" %} +[import, lang:"cpp"](code/cpp/flood_fill.cpp) {% sample lang="py" %} [import:, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} From 65599eed94658d039105c5c66ca386c11a3df8ff Mon Sep 17 00:00:00 2001 From: James Schloss Date: Wed, 20 Oct 2021 13:41:31 +0200 Subject: [PATCH 051/146] fixing chapter to use split-op code (#888) --- contents/quantum_systems/code/c++/energy.cpp | 59 ------------------ contents/quantum_systems/code/c/energy.c | 61 ------------------- .../quantum_systems/code/haskell/Energy.hs | 14 ----- contents/quantum_systems/code/julia/energy.jl | 18 ------ .../quantum_systems/code/python/energy.py | 17 ------ contents/quantum_systems/quantum_systems.md | 10 +-- 6 files changed, 5 insertions(+), 174 deletions(-) delete mode 100644 contents/quantum_systems/code/c++/energy.cpp delete mode 100644 contents/quantum_systems/code/c/energy.c delete mode 100644 contents/quantum_systems/code/haskell/Energy.hs delete mode 100644 contents/quantum_systems/code/julia/energy.jl delete mode 100644 contents/quantum_systems/code/python/energy.py diff --git a/contents/quantum_systems/code/c++/energy.cpp b/contents/quantum_systems/code/c++/energy.cpp deleted file mode 100644 index 15a58bd01..000000000 --- a/contents/quantum_systems/code/c++/energy.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#include - -void fft(std::vector> &x, bool inverse) { - std::vector> y(x.size(), std::complex(0.0, 0.0)); - - fftw_plan p; - - fftw_complex *in = reinterpret_cast(x.data()); - fftw_complex *out = reinterpret_cast(y.data()); - - p = fftw_plan_dft_1d(x.size(), in, out, - (inverse ? FFTW_BACKWARD : FFTW_FORWARD), FFTW_ESTIMATE); - - - fftw_execute(p); - fftw_destroy_plan(p); - - for (size_t i = 0; i < x.size(); ++i) { - x[i] = y[i] / sqrt(static_cast(x.size())); - } -} - -double calculate_energy(std::vector> wfc, - std::vector> h_r, - std::vector> h_k, - double dx, size_t size) { - std::vector> wfc_k(wfc); - std::vector> wfc_c(size); - fft(wfc_k, false); - - for (size_t i = 0; i < size; ++i) { - wfc_c[i] = conj(wfc[i]); - } - - std::vector> energy_k(size); - std::vector> energy_r(size); - - for (size_t i = 0; i < size; ++i) { - energy_k[i] = wfc_k[i] * pow(h_k[i], 2); - } - - fft(energy_k, true); - - for (size_t i = 0; i < size; ++i) { - energy_k[i] *= 0.5 * wfc_c[i]; - energy_r[i] = wfc_c[i] * h_r[i] * wfc[i]; - } - - double energy_final = 0; - - for (size_t i = 0; i < size; ++i) { - energy_final += real(energy_k[i] + energy_r[i]); - } - - return energy_final * dx; -} diff --git a/contents/quantum_systems/code/c/energy.c b/contents/quantum_systems/code/c/energy.c deleted file mode 100644 index 9086ffcd5..000000000 --- a/contents/quantum_systems/code/c/energy.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include - -#include - -void fft(double complex *x, int n, bool inverse) { - double complex y[n]; - memset(y, 0, sizeof(y)); - fftw_plan p; - - if (inverse) { - p = fftw_plan_dft_1d(n, (fftw_complex*)x, (fftw_complex*)y, - FFTW_BACKWARD, FFTW_ESTIMATE); - } else { - p = fftw_plan_dft_1d(n, (fftw_complex*)x, (fftw_complex*)y, - FFTW_FORWARD, FFTW_ESTIMATE); - } - - fftw_execute(p); - fftw_destroy_plan(p); - - for (size_t i = 0; i < n; ++i) { - x[i] = y[i] / sqrt((double)n); - } -} - -double calculate_energy(double complex *wfc, double complex *h_r, - double complex *h_k, double dx, size_t size) { - double complex wfc_k[size]; - double complex wfc_c[size]; - memcpy(wfc_k, wfc, sizeof(wfc_k)); - fft(wfc_k, size, false); - - for (size_t i = 0; i < size; ++i) { - wfc_c[i] = conj(wfc[i]); - } - - double complex energy_k[size]; - double complex energy_r[size]; - - for (size_t i = 0; i < size; ++i) { - energy_k[i] = wfc_k[i] * h_k[i]; - } - - fft(energy_k, size, true); - - for (size_t i = 0; i < size; ++i) { - energy_k[i] *= wfc_c[i]; - energy_r[i] = wfc_c[i] * h_r[i] * wfc[i]; - } - - double energy_final = 0; - - for (size_t i = 0; i < size; ++i) { - energy_final += creal(energy_k[i] + energy_r[i]); - } - - return energy_final * dx; -} diff --git a/contents/quantum_systems/code/haskell/Energy.hs b/contents/quantum_systems/code/haskell/Energy.hs deleted file mode 100644 index a024fd139..000000000 --- a/contents/quantum_systems/code/haskell/Energy.hs +++ /dev/null @@ -1,14 +0,0 @@ -import Data.Array.CArray -import Data.Complex -import Math.FFT (dft, idft) -- Binding to fftw - -type Vector = CArray Int (Complex Double) - -calculateEnergy :: Double -> Vector -> Vector -> Vector -> Double -calculateEnergy dx kin pot wfc = (* dx) . sum . map realPart $ elems total - where - total = liftArray2 (+) kineticE potentialE - potentialE = wfcConj .* pot .* wfc - kineticE = wfcConj .* idft (kin .* dft wfc) - wfcConj = liftArray conjugate wfc - a .* b = liftArray2 (*) a b diff --git a/contents/quantum_systems/code/julia/energy.jl b/contents/quantum_systems/code/julia/energy.jl deleted file mode 100644 index 3efce0cb7..000000000 --- a/contents/quantum_systems/code/julia/energy.jl +++ /dev/null @@ -1,18 +0,0 @@ -# We are calculating the energy to check -function calculate_energy(wfc, H_k, H_r, dx) - # Creating momentum and conjugate wavefunctions - wfc_k = fft(wfc) - wfc_c = conj(wfc) - - # Finding the momentum and real-space energy terms - energy_k = wfc_c.*ifft((H_k) .* wfc_k) - energy_r = wfc_c.* H_r .* wfc - - # Integrating over all space - energy_final = 0 - for i = 1:length(energy_k) - energy_final += real(energy_k[i] + energy_r[i]) - end - - return energy_final*dx -end diff --git a/contents/quantum_systems/code/python/energy.py b/contents/quantum_systems/code/python/energy.py deleted file mode 100644 index 328fa9950..000000000 --- a/contents/quantum_systems/code/python/energy.py +++ /dev/null @@ -1,17 +0,0 @@ -import numpy as np - - -def calculate_energy(wfc, H_k, H_r, dx): - """Calculate the energy .""" - # Creating momentum conjugate wavefunctions - wfc_k = np.fft.fft(wfc) - wfc_c = np.conj(wfc) - - # Finding the momentum and real-space energy terms - energy_k = 0.5 * wfc_c * np.fft.ifft((H_k ** 2) * wfc_k) - energy_r = wfc_c * H_r * wfc - - # Integrating over all space - energy_final = sum(energy_k + energy_r).real - - return energy_final * dx diff --git a/contents/quantum_systems/quantum_systems.md b/contents/quantum_systems/quantum_systems.md index a74c22068..a7a762ca5 100644 --- a/contents/quantum_systems/quantum_systems.md +++ b/contents/quantum_systems/quantum_systems.md @@ -226,15 +226,15 @@ This ultimately looks like this: {% method %} {% sample lang="jl" %} -[import, lang:"julia"](code/julia/energy.jl) +[import:114-132, lang:"julia"](../split-operator_method/code/julia/split_op.jl) {% sample lang="hs" %} -[import, lang:"haskell"](code/haskell/Energy.hs) +[import:75-82, lang:"haskell"](../split-operator_method/code/haskell/splitOp.hs) {% sample lang="c" %} -[import:29-, lang:"c"](code/c/energy.c) +[import:150-184, lang:"c"](../split-operator_method/code/c/split_op.c) {% sample lang="cpp" %} -[import:26-, lang:"cpp"](code/c++/energy.cpp) +[import:158-189, lang:"cpp"](../split-operator_method/code/c++/split_op.cpp) {% sample lang="py" %} -[import:4-17, lang:"python"](code/python/energy.py) +[import:98-112, lang:"python"](../split-operator_method/code/python/split_op.py) {% endmethod %} This calculation will be used in many different simulations of quantum systems to check our results. From 9eb11d52d1557a8eebb0cbc09b1da014e5f46bec Mon Sep 17 00:00:00 2001 From: PaddyKe <34421580+PaddyKe@users.noreply.github.com> Date: Sat, 23 Oct 2021 14:33:48 +0200 Subject: [PATCH 052/146] Implemented stacks and queues in Java (#897) --- .../stacks_and_queues/code/java/Queue.java | 71 ++++++++++++++++++ .../stacks_and_queues/code/java/Stack.java | 72 +++++++++++++++++++ .../stacks_and_queues/stacks_and_queues.md | 4 ++ 3 files changed, 147 insertions(+) create mode 100644 contents/stacks_and_queues/code/java/Queue.java create mode 100644 contents/stacks_and_queues/code/java/Stack.java diff --git a/contents/stacks_and_queues/code/java/Queue.java b/contents/stacks_and_queues/code/java/Queue.java new file mode 100644 index 000000000..bb349ec6d --- /dev/null +++ b/contents/stacks_and_queues/code/java/Queue.java @@ -0,0 +1,71 @@ +import java.util.List; +import java.util.ArrayList; + +public class QueueTest { + + public static void main(String[] args) { + IQueue intQueue = new Queue<>(); + + intQueue.enqueue(4); + intQueue.enqueue(5); + intQueue.enqueue(9); + + System.out.println(intQueue.dequeue()); + System.out.println(intQueue.size()); + System.out.println(intQueue.front()); + } + +} + + +interface IQueue { + + /* + * 'dequeue' removes the first element from the queue and returns it + */ + T dequeue(); + + /* + * 'enqueue' adds an element at the end of the queue and returns the new size + */ + int enqueue(T element); + + + /* + * 'size' returns the size of the queue + */ + int size(); + + /* + * 'front' returns the first element of the queue without removing it + */ + T front(); +} + + +public class Queue implements IQueue { + + private List list; + + public Queue() { + this.list = new ArrayList<>(); + } + + public T dequeue() { + return this.list.remove(0); + } + + public int enqueue(T element) { + this.list.add(element); + return this.size(); + } + + public int size() { + return this.list.size(); + } + + public T front() { + return this.list.get(0); + } + +} diff --git a/contents/stacks_and_queues/code/java/Stack.java b/contents/stacks_and_queues/code/java/Stack.java new file mode 100644 index 000000000..2d65a0e59 --- /dev/null +++ b/contents/stacks_and_queues/code/java/Stack.java @@ -0,0 +1,72 @@ +import java.util.List; +import java.util.ArrayList; + + +public class StackTest { + + public static void main(String[] args) { + IStack intStack = new Stack<>(); + + intStack.push(4); + intStack.push(5); + intStack.push(9); + + System.out.println(intStack.pop()); + System.out.println(intStack.size()); + System.out.println(intStack.top()); + } + +} + + +interface IStack { + /* + * 'pop' removed the last element from the stack and returns it + */ + T pop(); + + /* + * 'push' adds an element to at the end of the stack and returns the new size + */ + int push(T element); + + /* + * 'size' returns the length of the stack + */ + int size(); + + /* + * 'top' returns the first element of the stack + */ + T top(); +} + + +public class Stack implements IStack { + + private List list; + + public Stack() { + this.list = new ArrayList<>(); + } + + public T pop() { + return this.list.remove(this.size() - 1); + } + + public int push(T element) { + this.list.add(element); + return this.size(); + } + + public int size() { + return this.list.size(); + } + + public T top() { + return this.list.get(this.size() - 1); + } + +} + + diff --git a/contents/stacks_and_queues/stacks_and_queues.md b/contents/stacks_and_queues/stacks_and_queues.md index 11c7088f7..89a77be9a 100644 --- a/contents/stacks_and_queues/stacks_and_queues.md +++ b/contents/stacks_and_queues/stacks_and_queues.md @@ -18,12 +18,16 @@ Here is a simple implementation of a stack: {% method %} {% sample lang="ts" %} [import, lang:"typescript"](code/typescript/stack.ts) +{% sample lang="java" %} +[import, lang:"java"](code/java/Stack.java) {% endmethod %} Here is a simple implementation of a queue: {% method %} {% sample lang="ts" %} [import, lang:"typescript"](code/typescript/queue.ts) +{% sample lang="java" %} +[import, lang:"java" ](code/java/Queue.java) {% endmethod %} From 84e9d5d310acaf0b820a25819387e39e0cfb2acb Mon Sep 17 00:00:00 2001 From: Henrik Christensen Date: Sat, 23 Oct 2021 15:02:27 +0200 Subject: [PATCH 053/146] Java tree traversal: updated dfsRecursiveInOrderBinary (#899) --- contents/tree_traversal/code/java/Tree.java | 28 +++++++++++---------- contents/tree_traversal/tree_traversal.md | 12 ++++----- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/contents/tree_traversal/code/java/Tree.java b/contents/tree_traversal/code/java/Tree.java index 1dee7d9d1..b5c3d6542 100644 --- a/contents/tree_traversal/code/java/Tree.java +++ b/contents/tree_traversal/code/java/Tree.java @@ -1,4 +1,3 @@ -// submitted by xam4lor import java.util.ArrayList; import java.util.PriorityQueue; import java.util.Queue; @@ -45,19 +44,22 @@ public void dfsRecursiveInOrderBinary() { dfsRecursiveInOrderBinary(this.root); } - // This assumes only 2 children private void dfsRecursiveInOrderBinary(Node node) { - if (node.children.size() > 2) { - System.err.println("Not a binary tree at dfsRecursiveInOrderBinary()!"); - return; - } - - if (node.children.size() > 1) { - dfsRecursiveInOrderBinary(node.children.get(0)); - System.out.println(node.id); - dfsRecursiveInOrderBinary(node.children.get(1)); - } else { - System.out.println(node.id); + switch (node.children.size()) { + case 2: + dfsRecursiveInOrderBinary(node.children.get(0)); + System.out.println(node.id); + dfsRecursiveInOrderBinary(node.children.get(1)); + break; + case 1: + dfsRecursiveInOrderBinary(node.children.get(0)); + System.out.println(node.id); + break; + case 0: + System.out.println(node.id); + break; + default: + System.err.println("Not a binary tree at dfsRecursiveInOrderBinary()!"); } } diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index e03f09652..557cfdb55 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -12,7 +12,7 @@ Trees are naturally recursive data structures, and because of this, we cannot ac {% sample lang="c" %} [import:7-11, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:110-126, lang:"java"](code/java/Tree.java) +[import:112-128, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:1-10, lang:"javascript"](code/javascript/tree.js) As a note, a `node` struct is not necessary in javascript, so this is an example of how a tree might be constructed. @@ -58,7 +58,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="c" %} [import:37-45, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:21-27, lang:"java"](code/java/Tree.java) +[import:20-26, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:12-15, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} @@ -112,7 +112,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="c" %} [import:47-53, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:34-41, lang:"java"](code/java/Tree.java) +[import:33-40, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:17-20, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} @@ -161,7 +161,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="c" %} [import:55-73, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:48-62, lang:"java"](code/java/Tree.java) +[import:47-64, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:22-34, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} @@ -219,7 +219,7 @@ In code, it looks like this: {% sample lang="c" %} [import:75-93, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:65-79, lang:"java"](code/java/Tree.java) +[import:67-81, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:36-43, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} @@ -270,7 +270,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="c" %} [import:95-113, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} -[import:81-95, lang:"java"](code/java/Tree.java) +[import:83-97, lang:"java"](code/java/Tree.java) {% sample lang="js" %} [import:45-52, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} From 0652a18791c8a3548c227d790361554a36084b00 Mon Sep 17 00:00:00 2001 From: Neverik Date: Sat, 23 Oct 2021 16:09:29 +0300 Subject: [PATCH 054/146] Tree traversal in smalltalk (#453) --- .../code/smalltalk/tree_traversal.st | 81 +++++++++++++++++++ contents/tree_traversal/tree_traversal.md | 14 ++++ 2 files changed, 95 insertions(+) create mode 100644 contents/tree_traversal/code/smalltalk/tree_traversal.st diff --git a/contents/tree_traversal/code/smalltalk/tree_traversal.st b/contents/tree_traversal/code/smalltalk/tree_traversal.st new file mode 100644 index 000000000..411e5ff45 --- /dev/null +++ b/contents/tree_traversal/code/smalltalk/tree_traversal.st @@ -0,0 +1,81 @@ +Object subclass: #Node + instanceVariableNames: 'children data' + classVariableNames: '' + package: '' + +Node>>children + "Children getter." + ^ children + +Node>>children: newChildren + "Children setter." + children := newChildren. + +Node>>data + "Data getter" + ^ data + +Node>>data: newData + "Data setter" + data := newData. + +Node>>dfsRecursive + "Recursive depth first search." + Transcript show: data; cr. + children collect: [ :child | child dfsRecursive ] + +Node>>dfsRecursivePostOrder + "Recursive depth first search (post-order)." + children collect: [ :child | (child dfsRecursivePostOrder)]. + Transcript show: data; cr. + +Node>>dfsInOrderBinaryTree + "Recursive depth first search on a binary tree in order." + children size > 2 ifTrue: [ + Transcript show: 'This is not a binary tree!'; cr. + ^self. + ]. + children size = 2 ifTrue: [ + (children at: 1) dfsInOrderBinaryTree: value. + ]. + Transcript show: data; cr. + children size >= 1 ifTrue: [ + (children at: 0) dfsInOrderBinaryTree: value. + ]. + ^self. + +Node>>dfsStack + "Depth-first search with a stack." + | stack top | + stack := Stack new. + stack push: self. + [stack size > 0] whileTrue: [ + top := stack pop. + Transcript show: (top data); cr. + top children reverseDo: [ :child | + stack push: child. + ]. + ]. + +Node>>bfs + "A breadth-first tree search using queues." + | queue current | + queue := LinkedList with: self. + [ queue size > 0 ] whileTrue: [ + current := queue first. + queue removeFirst. + Transcript show: (current data); cr. + current children collect: [ :child | + queue addLast: child + ]. + ]. + +| test | +test := Node new: 1 children: { Node new: 2. + Node new: 3 children: { Node new: 4. + Node new: 5. } }. +test dfsRecursive. +test dfsRecursivePostorder. +test dfsInOrderBinaryTree. +test dfsStack. +test bfs. diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index 557cfdb55..c287b7612 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -32,6 +32,8 @@ As a note, a `node` struct is not necessary in javascript, so this is an example [import:4-37, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:1-5, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:1-20, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:5-8, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -77,6 +79,8 @@ Because of this, the most straightforward way to traverse the tree might be recu [import:41-49, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:7-10, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:22-27, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:10-15, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -131,6 +135,8 @@ Now, in this case the first element searched through is still the root of the tr [import:51-57, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:12-15, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:29-34, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:17-22, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -180,6 +186,8 @@ In this case, the first node visited is at the bottom of the tree and moves up t [import:59-78, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:17-31, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:36-49, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:24-38, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -238,6 +246,8 @@ In code, it looks like this: [import:80-91, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:33-41, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:47-58, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:40-49, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -289,6 +299,8 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can [import:93-104, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:43-51, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import:60-71, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import:51-60, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} @@ -351,6 +363,8 @@ The code snippets were taken from this [Scratch project](https://scratch.mit.edu [import, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import, lang:"crystal"](code/crystal/tree-traversal.cr) +{% sample lang="st" %} +[import, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} [import, lang:"go"](code/golang/treetraversal.go) {% sample lang="asm-x64" %} From f7e8e60dd6679bd1664e6c79e4b25b0be4589f15 Mon Sep 17 00:00:00 2001 From: PaddyKe <34421580+PaddyKe@users.noreply.github.com> Date: Sat, 23 Oct 2021 16:40:11 +0200 Subject: [PATCH 055/146] fixed print statements (#901) --- .../approximate_counting/code/c++/approximate_counting.cpp | 6 +++--- contents/approximate_counting/code/c/approximate_counting.c | 6 +++--- .../approximate_counting/code/julia/approximate_counting.jl | 6 +++--- .../code/python/approximate_counting.py | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contents/approximate_counting/code/c++/approximate_counting.cpp b/contents/approximate_counting/code/c++/approximate_counting.cpp index 7f3f1a16c..53f4641af 100644 --- a/contents/approximate_counting/code/c++/approximate_counting.cpp +++ b/contents/approximate_counting/code/c++/approximate_counting.cpp @@ -61,11 +61,11 @@ auto test_approximate_count( int main() { std::cout << "Counting Tests, 100 trials\n"; - std::cout << "testing 1,000, a = 30, 1% error " + std::cout << "testing 1,000, a = 30, 10% error " << test_approximate_count(100, 1000, 30, 0.1) << "\n"; - std::cout << "testing 12,345, a = 10, 1% error " + std::cout << "testing 12,345, a = 10, 10% error " << test_approximate_count(100, 12345, 10, 0.1) << "\n"; // Note : with a lower a, we need more trials, so a higher % error here. - std::cout << "testing 222,222, a = 0.5, 10% error " + std::cout << "testing 222,222, a = 0.5, 20% error " << test_approximate_count(100, 222222, 0.5, 0.2) << "\n"; } diff --git a/contents/approximate_counting/code/c/approximate_counting.c b/contents/approximate_counting/code/c/approximate_counting.c index ded7a518e..da44334a7 100644 --- a/contents/approximate_counting/code/c/approximate_counting.c +++ b/contents/approximate_counting/code/c/approximate_counting.c @@ -71,11 +71,11 @@ int main() srand(time(NULL)); printf("Counting Tests, 100 trials\n"); - printf("testing 1000, a = 30, 1%% error\n"); + printf("testing 1000, a = 30, 10%% error\n"); test_approximation_count(100, 1000, 30, 0.1); - printf("testing 12345, a = 10, 1%% error\n"); + printf("testing 12345, a = 10, 10%% error\n"); test_approximation_count(100, 12345, 10, 0.1); - printf("testing 222222, a = 0.5, 10%% error\n"); + printf("testing 222222, a = 0.5, 20%% error\n"); test_approximation_count(100, 222222, 0.5, 0.2); return 0; diff --git a/contents/approximate_counting/code/julia/approximate_counting.jl b/contents/approximate_counting/code/julia/approximate_counting.jl index 36b07651e..c6cf3b223 100644 --- a/contents/approximate_counting/code/julia/approximate_counting.jl +++ b/contents/approximate_counting/code/julia/approximate_counting.jl @@ -51,11 +51,11 @@ function test_approximate_count(n_trials, n_items, a, threshold) end @testset "Counting Tests, 100 trials" begin - println("testing 1,000, a = 30, 1% error") + println("testing 1,000, a = 30, 10% error") test_approximate_count(100, 1000, 30, 0.1) - println("testing 12,345, a = 10, 1% error") + println("testing 12,345, a = 10, 10% error") test_approximate_count(100, 12345, 10, 0.1) # Note: with a lower a, we need more trials, so a higher % error here. - println("testing 222,222, a = 0.5, 10% error") + println("testing 222,222, a = 0.5, 20% error") test_approximate_count(100, 222222, 0.5, 0.2) end diff --git a/contents/approximate_counting/code/python/approximate_counting.py b/contents/approximate_counting/code/python/approximate_counting.py index eb31b2b24..0088debcc 100644 --- a/contents/approximate_counting/code/python/approximate_counting.py +++ b/contents/approximate_counting/code/python/approximate_counting.py @@ -41,9 +41,9 @@ def test_approximate_count(n_trials, n_items, a, threshold): if abs((avg - n_items)/n_items) < threshold: print("passed") -print("testing 1,000, a = 30, 1% error") +print("testing 1,000, a = 30, 10% error") test_approximate_count(100, 1000, 30, 0.1) -print("testing 12,345, a = 10, 1% error") +print("testing 12,345, a = 10, 10% error") test_approximate_count(100, 12345, 10, 0.1) -print("testing 222,222, a = 0.5, 10% error") +print("testing 222,222, a = 0.5, 20% error") test_approximate_count(100, 222222, 0.5, 0.2) From 0fa638134628ae1911b5461df92369f02d6644b6 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sat, 23 Oct 2021 17:12:18 +0200 Subject: [PATCH 056/146] Fixes in PATH that make dlang, emojicode and factor usable (#890) --- .devcontainer/Dockerfile | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index bc58ae358..18af4df12 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -31,11 +31,10 @@ RUN sudo sh -c 'sudo dpkg -i packages-microsoft-prod.deb' RUN sudo sh -c 'rm packages-microsoft-prod.deb' # Setup D Lang -RUN sudo sh -c 'mkdir -p ~/dlang && wget https://dlang.org/install.sh -O ~/dlang/install.sh' -RUN sudo sh -c 'bash ~/dlang/install.sh' -## From Docs not needed though -# RUN sudo sh -c 'source ~/dlang/dmd-2.097.2/activate' -ENV PATH=$PATH:/root/dlang/dmd-2.097.2/linux/bin64 +ENV DLANG_VERSION=2.097.2 +RUN mkdir -p ~/dlang && wget https://dlang.org/install.sh -O ~/dlang/install.sh +RUN bash ~/dlang/install.sh dmd-$DLANG_VERSION +ENV PATH=$PATH:~/dlang/dmd-$DLANG_VERSION/linux/bin64/ # Setup Go RUN sudo sh -c 'wget -c https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local' @@ -56,17 +55,14 @@ ENV PATH=$PATH:/usr/local/kotlinc/bin # Setup Matlab # ?????? This is a licensed language??? -# Setup Emojicode (in progress) -RUN sudo sh -c 'wget -c https://github.com/emojicode/emojicode/releases/download/v1.0-beta.2/Emojicode-1.0-beta.2-Linux-x86_64.tar.gz -O /usr/local/Emojicode-1.0-beta.2-Linux-x86_64.tar.gz' -RUN sudo tar -xvzf /usr/local/Emojicode-1.0-beta.2-Linux-x86_64.tar.gz -# && cd ~/emojicode/ && echo && ./install.sh' -ENV PATH=$PATH:/usr/local/Emojicode-1.0-beta.2-Linux-x86_64 - -# Setup Factor (in progress) -RUN mkdir -p ~/factor && wget https://downloads.factorcode.org/releases/0.98/factor-linux-x86-64-0.98.tar.gz -O ~/factor/factor.tar.gz -RUN tar -xzf /root/factor/factor.tar.gz -# && rm ~/factor/factor.tar.gz -ENV PATH=$PATH:/root/factor/factor +# Setup Emojicode +RUN mkdir -p ~/emojicode && wget -c https://github.com/emojicode/emojicode/releases/download/v1.0-beta.2/Emojicode-1.0-beta.2-Linux-x86_64.tar.gz -O ~/emojicode/emojicode.tar.gz && \ + tar -xzf ~/emojicode/emojicode.tar.gz -C ~/emojicode --strip-components=1 +ENV PATH=$PATH:~/emojicode + +# Setup Factor +RUN mkdir -p ~/factor && wget https://downloads.factorcode.org/releases/0.98/factor-linux-x86-64-0.98.tar.gz -O ~/factor/factor.tar.gz && tar -xzf ~/factor/factor.tar.gz -C ~/factor --strip-components=1 +ENV PATH=$PATH:~/factor/factor # Setup R RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 From 44d8118d76223b90e1b53dfe37ae1fe7569c9a6b Mon Sep 17 00:00:00 2001 From: James Schloss Date: Sat, 23 Oct 2021 17:32:21 +0200 Subject: [PATCH 057/146] fixing huffman encoding for Julia and adding Test (#828) --- .../huffman_encoding/code/julia/huffman.jl | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/contents/huffman_encoding/code/julia/huffman.jl b/contents/huffman_encoding/code/julia/huffman.jl index 593d4b4f8..e01fd1dfd 100644 --- a/contents/huffman_encoding/code/julia/huffman.jl +++ b/contents/huffman_encoding/code/julia/huffman.jl @@ -1,3 +1,5 @@ +using Test + # This is for the PriorityQueue using DataStructures @@ -13,8 +15,6 @@ struct Branch end const Node = Union{Leaf, Branch} -isbranch(branch::Branch) = true -isbranch(other::T) where {T} = false function codebook_recurse!(leaf::Leaf, code::String, dict::Dict{Char,String}) @@ -33,7 +33,11 @@ end # This outputs encoding Dict to be used for encoding function create_codebook(n::Node) codebook = Dict{Char,String}() - codebook_recurse!(n, "", codebook) + if isa(n, Leaf) + codebook[n.key]="0" + else + codebook_recurse!(n, "", codebook) + end return codebook end @@ -85,14 +89,19 @@ function decode(huffman_tree::Node, bitstring::String) current = huffman_tree final_string = "" for i in bitstring - if (i == '1') - current = current.left + if isa(huffman_tree, Branch) + if (i == '1') + current = current.left + else + current = current.right + end + + if (!isa(current, Branch)) + final_string *= string(current.key) + current = huffman_tree + end else - current = current.right - end - if (!isbranch(current)) - final_string = final_string * string(current.key) - current = huffman_tree + final_string *= string(huffman_tree.key) end end @@ -102,11 +111,13 @@ end function two_pass_huffman(phrase::String) huffman_tree = create_tree(phrase) codebook = create_codebook(huffman_tree) - println(codebook) bitstring = encode(codebook, phrase) final_string = decode(huffman_tree, bitstring) - println(bitstring) - println(final_string) + return final_string end -two_pass_huffman("bibbity bobbity") +@testset "b-string tests" begin + @test two_pass_huffman("b") == "b" + @test two_pass_huffman("bbbbbbbb") == "bbbbbbbb" + @test two_pass_huffman("bibbity bobbity") == "bibbity bobbity" +end From cf56e67900a253a49cb8d98e595422493ca9a91c Mon Sep 17 00:00:00 2001 From: Henrik Christensen Date: Sat, 23 Oct 2021 22:06:45 +0200 Subject: [PATCH 058/146] JavaScript tree traversal: updated dfsInorder (#902) --- CONTRIBUTORS.md | 1 + .../tree_traversal/code/javascript/tree.js | 29 +++++++++++++++---- contents/tree_traversal/tree_traversal.md | 10 +++---- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e3707e290..9b2c1b460 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -60,3 +60,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Ridham177 - Hugo Salou - Dimitri Belopopsky ++ Henrik Abel Christensen diff --git a/contents/tree_traversal/code/javascript/tree.js b/contents/tree_traversal/code/javascript/tree.js index b6705bfdd..6670fe739 100644 --- a/contents/tree_traversal/code/javascript/tree.js +++ b/contents/tree_traversal/code/javascript/tree.js @@ -10,11 +10,19 @@ function createTree(rows, children) { } function dfsPreorder(tree) { + if (!tree) { + return; + } + console.log(tree.id); tree.children.forEach(dfsPreorder); } function dfsPostorder(tree) { + if (!tree) { + return; + } + tree.children.forEach(dfsPostorder); console.log(tree.id); } @@ -24,13 +32,22 @@ function dfsInorder(tree) { return; } - if (tree.children.length > 2) { - throw new Error("Postorder traversal is only valid for binary trees"); + switch (tree.children.length) { + case 2: + dfsInorder(tree.children[0]); + console.log(tree.id); + dfsInorder(tree.children[1]); + break; + case 1: + dfsInorder(tree.children[0]); + console.log(tree.id); + break; + case 0: + console.log(tree.id); + break; + default: + throw new Error("Postorder traversal is only valid for binary trees"); } - - dfsInorder(tree.children[0]); - console.log(tree.id); - dfsInorder(tree.children[1]); } function dfsIterative(tree) { diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index c287b7612..6d6504760 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -62,7 +62,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="java" %} [import:20-26, lang:"java"](code/java/Tree.java) {% sample lang="js" %} -[import:12-15, lang:"javascript"](code/javascript/tree.js) +[import:12-19, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} [import:18-23, lang:"python"](code/python/Tree_example.py) {% sample lang="scratch" %} @@ -118,7 +118,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="java" %} [import:33-40, lang:"java"](code/java/Tree.java) {% sample lang="js" %} -[import:17-20, lang:"javascript"](code/javascript/tree.js) +[import:21-28, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} [import:26-31, lang:"python"](code/python/Tree_example.py) {% sample lang="scratch" %} @@ -169,7 +169,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="java" %} [import:47-64, lang:"java"](code/java/Tree.java) {% sample lang="js" %} -[import:22-34, lang:"javascript"](code/javascript/tree.js) +[import:30-51, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} [import:34-46, lang:"python"](code/python/Tree_example.py) {% sample lang="scratch" %} @@ -229,7 +229,7 @@ In code, it looks like this: {% sample lang="java" %} [import:67-81, lang:"java"](code/java/Tree.java) {% sample lang="js" %} -[import:36-43, lang:"javascript"](code/javascript/tree.js) +[import:53-60, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} [import:49-60, lang:"python"](code/python/Tree_example.py) {% sample lang="scratch" %} @@ -282,7 +282,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="java" %} [import:83-97, lang:"java"](code/java/Tree.java) {% sample lang="js" %} -[import:45-52, lang:"javascript"](code/javascript/tree.js) +[import:62-69, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} [import:63-75, lang:"python"](code/python/Tree_example.py) {% sample lang="scratch" %} From 2000ab32125abe41907db41b1778a04355a234f0 Mon Sep 17 00:00:00 2001 From: Ishaan Verma Date: Mon, 25 Oct 2021 18:44:41 +0530 Subject: [PATCH 059/146] Tree Traversal: Output Standardization (#857) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pep8ify python * rename Tree_example.py * standardize python output * standardize c output * standardize c++ output * standardize rust output * standardize javascript output * standardize julia output * Standardized Coconut output * fix coconut * standardize go output * standardize common lisp output * Verlet Integration: Output standardization (#855) * Standardize julia output * Standardize kotlin output This also fixes a previous bug, which caused the time and velocity values to not get printed correctly. * Standardized c output * Standardized cpp output * Standardized lisp output * Standardized fortran output I was not able to prevent the preceding whitespaces, but they can just be trimmed. * Standardized go output * Standardized java output * Standardize javascript output * Standardize nim output * Standardize python output * Standardize ruby output As the original implementation only returned the time and not the velocity, the code needed to be adjusted a bit. Now it returns the two values as an array which gets deconstructed and printed. * Standardize rust output * Standardize swift output * Standardized haskell output * Standardized haskell output (no quote marks) * attempt at fix for asm Co-authored-by: Jérémie Gillet Co-authored-by: James Schloss * standardize php output * standardize swift output * removed outdated comments in Coconut implementation * standardize haskell output * Fix asm exit codes (#858) * standardize crystal output * Flood fill in Coconut (#836) * Added Barnsley fern in Coconut (+ .editorconfig for Coconut) (#814) * Added the Jarvis march in Coconut (#734) * Fix minor typo * Change folder structure of convolutions (#861) This puts every chapters' code into its own directory, which is useful for automatic validation. * standardize csharp output * standardize java output * fix php line numbers and python filename * fix coconut and python line numbers * fix minor bug in C * fix labels and minor bug in go * minor label fix in python * Huffman encoding in Coconut (#732) * Update README.md Changing readme link to reflect change in twitch url * Add C# implemenation for 1D Convolutions (#846) * Add C# implemenation for 1D Convolutions * Fix off by one error and julia line numbers * Fix off by one error for linear convolutions * Fix trailing zero * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Update contents/convolutions/code/csharp/1DConvolution.cs Co-authored-by: Trashtalk217 * Add trailing new line Co-authored-by: Trashtalk217 * IFS Common Lisp implementation (#722) * first working version * cleaned up the chaos-game function and added some helpfull comments * changed the .md file and upped iterations * Skeleton of the final solution * Update contents/IFS/IFS.md Co-authored-by: Eric Berquist Co-authored-by: James Schloss Co-authored-by: Eric Berquist * added MonteCarlo in PowerShell (#760) * Add Rust implementation for The Barnsley Fern (#818) * Add Rust implementation for The Barnsley Fern * Change operators constants and add Cargo.toml * Fix bug in matrix multiplication Co-authored-by: James Schloss * changing barnsley.md to read the correct coconut file (#867) * added approximate counting implementation in python (#866) * added approximate counting implementation in python * Update approximate_counting.py * updating approximate_counting.py * removed redundancies * fixing linking issues in convolution chapter (#868) * Add initial devcontainer (#862) * small changes to convolutional theorem chapter and code to make things more reproduceable (#872) * added convolutional theorem implementation in python (#869) * added convolutional theorem implementation in python * fixed chapter linking * added comments to the code * changed random distribution to sawtooth * corrected previous commit * fixed comments Co-authored-by: James Schloss * Use `[#]\n` instead of `[#]` for human readable output (#873) * Add approximate counting algorithm in C (#844) * Add approximate counting algorithm in C * Fix typo Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: James Schloss * added 1d convolution implementation in python (#874) * added 1d convolution implementation in python * fixed some mistakes in the code so it outputs correct results * making the code look better * spacing code properly for readability * fixing 1d convolution markdown file (#879) * Add racket setup to devcontainer (#875) * Normalize inputs for scheme euclid algorithm (#878) Change inputs to make it consistent with other examples. * Add initial setup for Swift in devcontainer (#880) * Add scheme setup to devcontainer (#876) * Clean up Monte Carlo integration in Racket (#781) * Clean up Monte Carlo integration in Racket * Add blank lines in Monte Carlo integration in Clojure * Change Racket lang include from lisp to racket * Add C++ code for Flood Fill algorithm (#860) * fixing chapter to use split-op code (#888) * use [#]\n for readability * Implemented stacks and queues in Java (#897) * Java tree traversal: updated dfsRecursiveInOrderBinary (#899) * Tree traversal in smalltalk (#453) * fixed print statements (#901) * Fixes in PATH that make dlang, emojicode and factor usable (#890) * fixing huffman encoding for Julia and adding Test (#828) * JavaScript tree traversal: updated dfsInorder (#902) * julia: change printf to print * pep8ify python * rename Tree_example.py * standardize python output * standardize c output * standardize c++ output * standardize rust output * standardize javascript output Resolved conflict with master (by Amaras) * standardize julia output Resolved conflict with master (by Amaras) * Standardized Coconut output * fix coconut * standardize go output * standardize common lisp output * standardize php output * standardize swift output * removed outdated comments in Coconut implementation * standardize haskell output * standardize crystal output * standardize csharp output * standardize java output Resolved the conflict with fixing dfs * fix php line numbers and python filename * fix coconut and python line numbers * fix minor bug in C * fix labels and minor bug in go * minor label fix in python * use [#]\n for readability * julia: change printf to print * update Tree.java. remove MainClass.java Co-authored-by: Sammy Plat Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: Jérémie Gillet Co-authored-by: James Schloss Co-authored-by: Eric Berquist Co-authored-by: Trashtalk217 Co-authored-by: PaddyKe <34421580+PaddyKe@users.noreply.github.com> Co-authored-by: Dimitri Belopopsky Co-authored-by: Ayman Lafaz Co-authored-by: Nicholas Tindle Co-authored-by: Mahdi <24981501+mahdisarikhani@users.noreply.github.com> Co-authored-by: Henrik Christensen Co-authored-by: Neverik --- .../tree_traversal/code/c++/tree_example.cpp | 33 +++--- .../tree_traversal/code/c/tree_traversal.c | 38 +++++-- .../code/clisp/tree-traversal.lisp | 19 ++-- .../code/coconut/tree_traversal.coco | 21 ++-- .../code/crystal/tree-traversal.cr | 50 ++------- .../tree_traversal/code/csharp/Program.cs | 26 +++-- contents/tree_traversal/code/csharp/Tree.cs | 18 +-- .../tree_traversal/code/csharp/code.csproj | 9 ++ .../code/golang/treetraversal.go | 40 ++++--- .../code/haskell/TreeTraversal.hs | 47 ++++---- .../tree_traversal/code/java/MainClass.java | 34 ++++++ contents/tree_traversal/code/java/Tree.java | 58 +++++----- .../tree_traversal/code/javascript/tree.js | 23 +++- contents/tree_traversal/code/julia/Tree.jl | 34 +++--- .../code/php/tree_traversal.php | 44 ++++---- .../code/python/Tree_example.py | 99 ----------------- .../code/python/tree_traversal.py | 103 ++++++++++++++++++ contents/tree_traversal/code/rust/tree.rs | 35 +++--- contents/tree_traversal/code/swift/tree.swift | 31 +++--- contents/tree_traversal/tree_traversal.md | 36 +++--- 20 files changed, 442 insertions(+), 356 deletions(-) create mode 100644 contents/tree_traversal/code/csharp/code.csproj create mode 100644 contents/tree_traversal/code/java/MainClass.java delete mode 100644 contents/tree_traversal/code/python/Tree_example.py create mode 100644 contents/tree_traversal/code/python/tree_traversal.py diff --git a/contents/tree_traversal/code/c++/tree_example.cpp b/contents/tree_traversal/code/c++/tree_example.cpp index 9f2dd80e1..71a84c686 100644 --- a/contents/tree_traversal/code/c++/tree_example.cpp +++ b/contents/tree_traversal/code/c++/tree_example.cpp @@ -17,7 +17,7 @@ struct node { // Simple recursive scheme for DFS void dfs_recursive(node const& n) { // Here we are doing something... - std::cout << n.value << '\n'; + std::cout << n.value << ' '; for (auto const& child : n.children) { dfs_recursive(child); } @@ -27,7 +27,7 @@ void dfs_recursive_postorder(node const& n) { for (auto const& child : n.children) { dfs_recursive_postorder(child); } - std::cout << n.value << '\n'; + std::cout << n.value << ' '; } @@ -35,15 +35,15 @@ void dfs_recursive_inorder_btree(node const& n) { switch (n.children.size()) { case 2: dfs_recursive_inorder_btree(n.children[0]); - std::cout << n.value << '\n'; + std::cout << n.value << ' '; dfs_recursive_inorder_btree(n.children[1]); break; case 1: dfs_recursive_inorder_btree(n.children[0]); - std::cout << n.value << '\n'; + std::cout << n.value << ' '; break; case 0: - std::cout << n.value << '\n'; + std::cout << n.value << ' '; break; default: std::cout << "This is not a binary tree.\n"; @@ -61,7 +61,7 @@ void dfs_stack(node const& n) { while (stack.size() > 0) { auto const& temp = *stack.top(); stack.pop(); - std::cout << temp.value << '\n'; + std::cout << temp.value << ' '; for (auto const& child : temp.children) { stack.push(&child); @@ -78,7 +78,7 @@ void bfs_queue(node const& n) { auto const& temp = *queue.front(); queue.pop(); - std::cout << temp.value << '\n'; + std::cout << temp.value << ' '; for (auto const& child : temp.children) { queue.push(&child); } @@ -100,18 +100,23 @@ node create_tree(size_t num_row, size_t num_child) { int main() { // Creating Tree in main - auto root = create_tree(3, 3); + auto root = create_tree(2, 3); auto binary_root = create_tree(3, 2); - std::cout << "DFS recursive:\n"; + std::cout << "[#]\nRecursive DFS:\n"; dfs_recursive(root); - std::cout << "DFS post order recursive:\n"; + std::cout << '\n'; + std::cout << "[#]\nRecursive Postorder DFS:\n"; dfs_recursive_postorder(root); - std::cout << "DFS inorder binary tree:\n"; - dfs_recursive_inorder_btree(binary_root); - std::cout << "DFS stack:\n"; + std::cout << '\n'; + std::cout << "[#]\nStack-based DFS:\n"; dfs_stack(root); - std::cout << "BFS queue:\n"; + std::cout << '\n'; + std::cout << "[#]\nQueue-based BFS:\n"; bfs_queue(root); + std::cout << '\n'; + std::cout << "[#]\nRecursive Inorder DFS for Binary Tree:\n"; + dfs_recursive_inorder_btree(binary_root); + std::cout << '\n'; return 0; } diff --git a/contents/tree_traversal/code/c/tree_traversal.c b/contents/tree_traversal/code/c/tree_traversal.c index 7fed9a16c..16be536c8 100644 --- a/contents/tree_traversal/code/c/tree_traversal.c +++ b/contents/tree_traversal/code/c/tree_traversal.c @@ -35,7 +35,7 @@ void destroy_tree(struct node n) { } void dfs_recursive(struct node n) { - printf("%d\n", n.id); + printf("%d ", n.id); if (n.children) { for (size_t i = 0; i < n.children_size; ++i) { @@ -49,22 +49,22 @@ void dfs_recursive_postorder(struct node n) { dfs_recursive_postorder(n.children[i]); } - printf("%d\n", n.id); + printf("%d ", n.id); } void dfs_recursive_inorder_btree(struct node n) { switch (n.children_size) { case 2: dfs_recursive_inorder_btree(n.children[0]); - printf("%d\n", n.id); + printf("%d ", n.id); dfs_recursive_inorder_btree(n.children[1]); break; case 1: dfs_recursive_inorder_btree(n.children[0]); - printf("%d\n", n.id); + printf("%d ", n.id); break; case 0: - printf("%d\n", n.id); + printf("%d ", n.id); break; default: printf("This is not a binary tree.\n"); @@ -83,7 +83,7 @@ void dfs_stack(struct node n) { break; } - printf("%d\n", tmp->id); + printf("%d ", tmp->id); for (size_t i = 0; i < tmp->children_size; ++i) { stack_push(&stk, &tmp->children[i]); } @@ -103,7 +103,7 @@ void bfs_queue(struct node n) { break; } - printf("%d\n", tmp->id); + printf("%d ", tmp->id); for (size_t i = 0; i < tmp->children_size; ++i) { enqueue(&q, &tmp->children[i]); } @@ -113,9 +113,31 @@ void bfs_queue(struct node n) { } int main() { - struct node root = create_tree(3, 3); + struct node root = create_tree(2, 3); + + printf("[#]\nRecursive DFS:\n"); + dfs_recursive(root); + printf("\n"); + + printf("[#]\nRecursive Postorder DFS:\n"); + dfs_recursive_postorder(root); + printf("\n"); + + printf("[#]\nStack-based DFS:\n"); + dfs_stack(root); + printf("\n"); + + printf("[#]\nQueue-based BFS:\n"); bfs_queue(root); + printf("\n"); + destroy_tree(root); + struct node root_binary = create_tree(3, 2); + printf("[#]\nRecursive Inorder DFS for Binary Tree:\n"); + dfs_recursive_inorder_btree(root_binary); + printf("\n"); + + destroy_tree(root_binary); return 0; } diff --git a/contents/tree_traversal/code/clisp/tree-traversal.lisp b/contents/tree_traversal/code/clisp/tree-traversal.lisp index 417a6f242..8c74db43b 100644 --- a/contents/tree_traversal/code/clisp/tree-traversal.lisp +++ b/contents/tree_traversal/code/clisp/tree-traversal.lisp @@ -58,36 +58,41 @@ (defun make-tree (num-rows num-child) "Creates a simple tree, where every node has 'num-child' children and is 'num-rows' deep." ;; A tree with 0 rows can't be created. - (if (eql num-rows 1) + (if (eql num-rows 0) (make-node - :data 1 + :data 0 :children nil) (make-node :data num-rows :children (loop repeat num-child collect (make-tree (1- num-rows) num-child))))) ;; A tree for testing -(defvar tree (make-tree 3 3)) +(defvar tree (make-tree 2 3)) ;; A binary tree for testing (defvar binary-tree (make-tree 3 2)) ;; Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 +(format t "[#]~%Recursive DFS:~%") (dfs-recursive tree) (format t "~%") ;; Should print: 1 1 1 2 1 1 1 2 1 1 1 2 3 +(format t "[#]~%Recursive Postorder DFS:~%") (dfs-recursive-postorder tree) (format t "~%") -;; Should print: 1 2 1 3 1 2 1 -(dfs-recursive-inorder-btree binary-tree) -(format t "~%") - ;; Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 +(format t "[#]~%Stack-based DFS:~%") (dfs-stack tree) (format t "~%") ;; Should print: 3 2 2 2 1 1 1 1 1 1 1 1 1 +(format t "[#]~%Queue-based BFS:~%") (bfs-queue tree) (format t "~%") + +;; Should print: 1 2 1 3 1 2 1 +(format t "[#]~%Recursive Inorder DFS for Binary Tree:~%") +(dfs-recursive-inorder-btree binary-tree) +(format t "~%") diff --git a/contents/tree_traversal/code/coconut/tree_traversal.coco b/contents/tree_traversal/code/coconut/tree_traversal.coco index c7433fea2..776708f6e 100644 --- a/contents/tree_traversal/code/coconut/tree_traversal.coco +++ b/contents/tree_traversal/code/coconut/tree_traversal.coco @@ -50,8 +50,8 @@ def bfs_queue(node is Node): def create_tree(num_rows, num_child): """Creates a simple tree, where every node has 'num_child' children and is 'num_rows' deep.""" - if num_rows == 1: - return Node(1, ()) + if num_rows == 0: + return Node(0, ()) else: return Node(num_rows, tuple(create_tree(num_rows-1, num_child) for _ in range(num_child))) @@ -59,33 +59,28 @@ def create_tree(num_rows, num_child): if __name__ =='__main__': # A ternary tree for testing - tree = create_tree(3, 3) + tree = create_tree(2, 3) - # Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 - print("Recursive DFS:") + print("[#]\nRecursive DFS:") dfs_recursive(tree) print() - # Should print: 1 1 1 2 1 1 1 2 1 1 1 2 3 - print("Recursive Postorder DFS:") + print("[#]\nRecursive Postorder DFS:") dfs_recursive_postorder(tree) print() - # Should print: 3 2 1 1 1 2 1 1 1 2 1 1 1 - print("Stack (DFS):") + print("[#]\nStack-based DFS:") dfs_stack(tree) print() - # Should print: 3 2 2 2 1 1 1 1 1 1 1 1 1 - print("Queue (BFS):") + print("[#]\nQueue-based BFS:") bfs_queue(tree) print() # And a binary tree for testing binary_tree = create_tree(3, 2) - # Should print: 1 2 1 3 1 2 1 - print("Recursive Inorder Binary Tree:") + print("[#]\nRecursive Inorder DFS for Binary Tree:") dfs_recursive_inorder_btree(binary_tree) print() diff --git a/contents/tree_traversal/code/crystal/tree-traversal.cr b/contents/tree_traversal/code/crystal/tree-traversal.cr index e3556d8eb..e63dbbb7e 100644 --- a/contents/tree_traversal/code/crystal/tree-traversal.cr +++ b/contents/tree_traversal/code/crystal/tree-traversal.cr @@ -5,26 +5,26 @@ class Node end def dfs_recursive(node) - print node.id + print "#{node.id} " node.children.each{ |child| dfs_recursive child } end def dfs_recursive_postorder(node) node.children.each{ |child| dfs_recursive_postorder child } - print node.id + print "#{node.id} " end def dfs_recursive_inorder_btree(node) case node.children.size when 2 dfs_recursive_inorder_btree node.children[0] - print node.id + print "#{node.id} " dfs_recursive_inorder_btree node.children[1] when 1 dfs_recursive_inorder_btree node.children[0] - print node.id + print "#{node.id} " when 0 - print node.id + print "#{node.id} " else print "Not a binary tree!" end @@ -35,7 +35,7 @@ def dfs_stack(node) until stack.empty? temp = stack.pop - print temp.id + print "#{temp.id} " temp.children.each{ |child| stack.push child } end end @@ -45,7 +45,7 @@ def bfs_queue(node) until queue.empty? temp = queue.shift - print temp.id + print "#{temp.id} " temp.children.each{ |child| queue.push child } end end @@ -60,54 +60,28 @@ def create_tree(levels, num_childs) Node.new(levels, children) end -def print_tree(node, depth = [] of String) - puts "(#{node.id})" - depth.push " " - len = node.children.size - 1 - - (0 .. len).each do |i| - depth.each{|c| print c} - unless i == len - print "├" - depth.push "│" - print_tree node.children[i], depth - depth.pop - else - print "â””" - depth.push " " - print_tree node.children[i], depth - depth.pop - end - end - depth.pop -end - def main - puts "Creating Tree" root = create_tree levels: 2, num_childs: 3 - print_tree root - puts "Using recursive DFS:" + puts "[#]\nRecursive DFS:" dfs_recursive root puts - puts "Using recursive DFS with post-order traversal:" + puts "[#]\nRecursive Postorder DFS:" dfs_recursive_postorder root puts - puts "Using stack-based DFS:" + puts "[#]\nStack-based DFS:" dfs_stack root puts - puts "Using queue-based BFS:" + puts "[#]\nQueue-based BFS:" bfs_queue root puts - puts "Creating binary tree to test in-order traversal" root_bin = create_tree levels: 3, num_childs: 2 - print_tree root_bin - puts "Using In-order DFS:" + puts "[#]\nRecursive Inorder DFS for Binary Tree:" dfs_recursive_inorder_btree root_bin puts end diff --git a/contents/tree_traversal/code/csharp/Program.cs b/contents/tree_traversal/code/csharp/Program.cs index aa2df0485..4308794dd 100644 --- a/contents/tree_traversal/code/csharp/Program.cs +++ b/contents/tree_traversal/code/csharp/Program.cs @@ -7,23 +7,27 @@ class Program { static void Main(string[] args) { - Console.WriteLine("TreeTraversal"); - var tree = new Tree(3, 3); - Console.WriteLine("DFSRecursive:"); + var tree = new Tree(2, 3); + Console.WriteLine("[#]\nRecursive DFS:"); tree.DFSRecursive(); - Console.WriteLine("DFSStack:"); + Console.WriteLine(); + + Console.WriteLine("[#]\nRecursive Postorder DFS:"); + tree.DFSRecursivePostorder(); + Console.WriteLine(); + + Console.WriteLine("[#]\nStack-based DFS:"); tree.DFSStack(); - Console.WriteLine("BFSQueue:"); + Console.WriteLine(); + + Console.WriteLine("[#]\nQueue-based BFS:"); tree.BFSQueue(); - Console.WriteLine("DFSRecursivePostorder"); - tree.DFSRecursivePostorder(); + Console.WriteLine(); - // Uncommenting the following 2 lines will result in an exception thrown because at least one Node of the Tree has more than 2 children and therefor a DFSRecursiveInorderBinary doesn't work. - // Console.WriteLine("DFSRecursiveInorder (fail)"); - // tree.DFSRecursiveInorderBinary(); tree = new Tree(3, 2); - Console.WriteLine("DFSRecursiveInorder (succeed)"); + Console.WriteLine("[#]\nRecursive Inorder DFS for Binary Tree:"); tree.DFSRecursiveInorderBinary(); + Console.WriteLine(); } } } diff --git a/contents/tree_traversal/code/csharp/Tree.cs b/contents/tree_traversal/code/csharp/Tree.cs index e38be26fc..f581008d7 100644 --- a/contents/tree_traversal/code/csharp/Tree.cs +++ b/contents/tree_traversal/code/csharp/Tree.cs @@ -11,12 +11,12 @@ public class Tree public Tree(int depthCount, int childrenCount) { - this.Id = 1; + this.Id = depthCount; - if (!(depthCount <= 1)) + if (depthCount > 0) { for (int i = 0; i < childrenCount; i++) - this._children.Add(new Tree(this.Id * 10 + i + 1, depthCount - 1, childrenCount)); + this._children.Add(new Tree(depthCount - 1, childrenCount)); } } @@ -37,7 +37,7 @@ public void DFSRecursive() void DFSRecursive(Tree tree) { - Console.WriteLine(tree.Id); + Console.Write(tree.Id + " "); foreach (var c in tree._children) DFSRecursive(c); @@ -53,7 +53,7 @@ void DFSRecursivePostorder(Tree tree) foreach (var c in tree._children) DFSRecursivePostorder(c); - Console.WriteLine(tree.Id); + Console.Write(tree.Id + " "); } } @@ -70,11 +70,11 @@ void DFSRecursiveInorderBinary(Tree tree) if (tree._children.Count > 0) { DFSRecursiveInorderBinary(tree._children[0]); - Console.WriteLine(tree.Id); + Console.Write(tree.Id + " "); DFSRecursiveInorderBinary(tree._children[1]); } else - Console.WriteLine(tree.Id); + Console.Write(tree.Id + " "); } } @@ -85,7 +85,7 @@ public void DFSStack() while (stack.Count != 0) { - Console.WriteLine(stack.Peek().Id); + Console.Write(stack.Peek().Id + " "); var temp = stack.Pop(); foreach (var c in temp._children) @@ -100,7 +100,7 @@ public void BFSQueue() while (queue.Count != 0) { - Console.WriteLine(queue.Peek().Id); + Console.Write(queue.Peek().Id + " "); var temp = queue.Dequeue(); foreach (var c in temp._children) diff --git a/contents/tree_traversal/code/csharp/code.csproj b/contents/tree_traversal/code/csharp/code.csproj new file mode 100644 index 000000000..98c5e6713 --- /dev/null +++ b/contents/tree_traversal/code/csharp/code.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + false + + + diff --git a/contents/tree_traversal/code/golang/treetraversal.go b/contents/tree_traversal/code/golang/treetraversal.go index 548f552f7..fb5142712 100644 --- a/contents/tree_traversal/code/golang/treetraversal.go +++ b/contents/tree_traversal/code/golang/treetraversal.go @@ -8,7 +8,7 @@ type node struct { } func dfsRecursive(n *node) { - fmt.Println(n.id) + fmt.Printf("%d ", n.id) for _, child := range n.children { dfsRecursive(child) } @@ -16,22 +16,22 @@ func dfsRecursive(n *node) { func dfsRecursivePostorder(n *node) { for _, child := range n.children { - dfsRecursive(child) + dfsRecursivePostorder(child) } - fmt.Println(n.id) + fmt.Printf("%d ", n.id) } func dfsRecursiveInorderBtree(n *node) { switch len(n.children) { case 2: dfsRecursiveInorderBtree(n.children[0]) - fmt.Println(n.id) + fmt.Printf("%d ", n.id) dfsRecursiveInorderBtree(n.children[1]) case 1: dfsRecursiveInorderBtree(n.children[0]) - fmt.Println(n.id) + fmt.Printf("%d ", n.id) case 0: - fmt.Println(n.id) + fmt.Printf("%d ", n.id) default: fmt.Println("This is not a binary tree") } @@ -43,7 +43,7 @@ func dfsStack(n *node) { for len(stack) > 0 { cur := stack[0] stack = stack[1:] - fmt.Println(cur.id) + fmt.Printf("%d ", cur.id) stack = append(cur.children, stack...) } } @@ -54,7 +54,7 @@ func bfsQueue(n *node) { for len(queue) > 0 { cur := queue[0] queue = queue[1:] - fmt.Println(cur.id) + fmt.Printf("%d ", cur.id) queue = append(queue, cur.children...) } } @@ -74,17 +74,27 @@ func createTree(numRow, numChild int) *node { } func main() { - root := createTree(3, 3) + root := createTree(2, 3) binTree := createTree(3, 2) - fmt.Println("DFS recursive:") + fmt.Println("[#]\nRecursive DFS:") dfsRecursive(root) - fmt.Println("DFS post order recursive:") + fmt.Println() + + fmt.Println("[#]\nRecursive Postorder DFS:") dfsRecursivePostorder(root) - fmt.Println("DFS inorder binary tree:") - dfsRecursiveInorderBtree(binTree) - fmt.Println("DFS stack:") + fmt.Println() + + fmt.Println("[#]\nStack-based DFS:") dfsStack(root) - fmt.Println("BFS queue:") + fmt.Println() + + fmt.Println("[#]\nQueue-based BFS:") bfsQueue(root) + fmt.Println() + + fmt.Println("[#]\nRecursive Inorder DFS for Binary Tree:") + dfsRecursiveInorderBtree(binTree) + fmt.Println() + } diff --git a/contents/tree_traversal/code/haskell/TreeTraversal.hs b/contents/tree_traversal/code/haskell/TreeTraversal.hs index 389dc0900..1f9d27db8 100644 --- a/contents/tree_traversal/code/haskell/TreeTraversal.hs +++ b/contents/tree_traversal/code/haskell/TreeTraversal.hs @@ -1,7 +1,8 @@ data Tree a = Node - { node :: a - , forest :: [Tree a] - } deriving (Show) + { node :: a, + forest :: [Tree a] + } + deriving (Show) dfs :: Tree a -> [a] dfs (Node x ts) = x : concatMap dfs ts @@ -19,7 +20,7 @@ dfsStack :: Tree a -> [a] dfsStack t = go [t] where go [] = [] - go ((Node x ts):stack) = x : go (ts ++ stack) + go ((Node x ts) : stack) = x : go (ts ++ stack) bfs :: Tree a -> [a] bfs (Node x ts) = x : go ts @@ -27,26 +28,22 @@ bfs (Node x ts) = x : go ts go [] = [] go ts = map node ts ++ go (concatMap forest ts) -toBin :: Tree a -> Tree a -toBin (Node x ts) = Node x (map toBin $ take 2 ts) +createTree :: Int -> Int -> Tree Int +createTree 0 _ = Node 0 [] +createTree numRow numChild = Node numRow children + where + children = map (createTree (numRow - 1)) $ replicate numChild numChild main = do - print $ dfs testTree - print $ dfsPostOrder testTree - print $ dfsInOrder $ toBin testTree - print $ dfsStack testTree - print $ bfs testTree - -testTree :: Tree Int -testTree = - Node - 1 - [ Node 2 [Node 3 [], Node 4 [Node 5 []]] - , Node - 6 - [ Node 7 [] - , Node 8 [Node 9 [Node 10 [Node 11 []], Node 12 []]] - , Node 13 [Node 14 []] - ] - , Node 15 [] - ] + let testTree = createTree 2 3 + showNodes = unwords . map show + putStrLn "[#]\nRecursive DFS:" + putStrLn $ showNodes $ dfs testTree + putStrLn "[#]\nRecursive Postorder DFS:" + putStrLn $ showNodes $ dfsPostOrder testTree + putStrLn "[#]\nStack-based DFS:" + putStrLn $ showNodes $ dfsStack testTree + putStrLn "[#]\nQueue-based BFS:" + putStrLn $ showNodes $ bfs testTree + putStrLn "[#]\nRecursive Inorder DFS for Binary Tree:" + putStrLn $ showNodes $ dfsInOrder $ createTree 3 2 diff --git a/contents/tree_traversal/code/java/MainClass.java b/contents/tree_traversal/code/java/MainClass.java new file mode 100644 index 000000000..d7c062c03 --- /dev/null +++ b/contents/tree_traversal/code/java/MainClass.java @@ -0,0 +1,34 @@ +//submitted by xam4lor +public class MainClass { + public static void main(String[] args) { + Tree tree = new Tree(2, 3); + + System.out.println("[#]\nRecursive DFS:"); + tree.dfsRecursive(); + System.out.println(); + + System.out.println("[#]\nRecursive Postorder DFS:"); + tree.dfsRecursivePostOrder(); + System.out.println(); + + + System.out.println("[#]\nStack-based DFS:"); + tree.dfsStack(); + System.out.println(); + + + System.out.println("[#]\nQueue-based BFS:"); + tree.bfsQueue(); + System.out.println(); + + + // Uncommenting the following 2 lines will result in an exception thrown because at least one Node of the Tree has more than 2 children and therefor a DFSRecursiveInorderBinary doesn't work. + //System.out.println("Using in-order binary recursive DFS : (fail)"); + //tree.dfsRecursiveInOrderBinary(); + + tree = new Tree(3, 2); + System.out.println("[#]\nRecursive Inorder DFS for Binary Tree:"); + tree.dfsRecursiveInOrderBinary(); + System.out.println(); + } +} diff --git a/contents/tree_traversal/code/java/Tree.java b/contents/tree_traversal/code/java/Tree.java index b5c3d6542..93e508f6c 100644 --- a/contents/tree_traversal/code/java/Tree.java +++ b/contents/tree_traversal/code/java/Tree.java @@ -1,5 +1,5 @@ import java.util.ArrayList; -import java.util.PriorityQueue; +import java.util.LinkedList; import java.util.Queue; import java.util.Stack; @@ -8,8 +8,8 @@ public class Tree { public Tree(int rowCount, int childrenCount) { // this.root is the root node of the Tree - this.root = new Node(1); - this.createAllChildren(this.root, rowCount, childrenCount); + this.root = new Node(rowCount); + this.createAllChildren(this.root, rowCount-1, childrenCount); } @@ -18,7 +18,7 @@ public void dfsRecursive() { } private void dfsRecursive(Node node) { - System.out.println(node.id); + System.out.print(node.id + " "); for (Node n : node.children) { dfsRecursive(n); @@ -36,7 +36,7 @@ private void dfsRecursivePostOrder(Node node) { } // Here we are doing something ... - System.out.println(node.id); + System.out.print(node.id + " "); } @@ -48,15 +48,15 @@ private void dfsRecursiveInOrderBinary(Node node) { switch (node.children.size()) { case 2: dfsRecursiveInOrderBinary(node.children.get(0)); - System.out.println(node.id); + System.out.print(node.id + " "); dfsRecursiveInOrderBinary(node.children.get(1)); break; case 1: dfsRecursiveInOrderBinary(node.children.get(0)); - System.out.println(node.id); + System.out.print(node.id + " "); break; case 0: - System.out.println(node.id); + System.out.print(node.id + " "); break; default: System.err.println("Not a binary tree at dfsRecursiveInOrderBinary()!"); @@ -71,7 +71,7 @@ public void dfsStack() { Node tmp; while (stack.size() != 0) { - System.out.println(stack.peek().id); + System.out.print(stack.peek().id + " "); tmp = stack.pop(); for (Node c : tmp.children) { @@ -81,11 +81,11 @@ public void dfsStack() { } public void bfsQueue() { - Queue queue = new PriorityQueue(); + Queue queue = new LinkedList(); queue.add(this.root); while (queue.size() != 0) { - System.out.println(queue.peek().id); + System.out.print(queue.peek().id + " "); Node temp = queue.poll(); // return null if the queue is empty if (temp != null) { @@ -98,12 +98,12 @@ public void bfsQueue() { private void createAllChildren(Node node, int rowCount, int childrenCount) { - if (rowCount <= 1) { + if (rowCount < 0) { return; } for (int i = 0; i < childrenCount; i++) { - node.children.add(new Node(node.id * 10 + i + 1)); + node.children.add(new Node(rowCount)); createAllChildren(node.children.get(i), rowCount - 1, childrenCount); } } @@ -128,32 +128,34 @@ public int compareTo(Node other) { } public static void main(String[] args) { - System.out.println("Creating Tree"); - Tree tree = new Tree(3, 3); + Tree tree = new Tree(2, 3); - System.out.println("Using recursive DFS :"); + System.out.println("[#]\nRecursive DFS:"); tree.dfsRecursive(); + System.out.println(); - System.out.println("Using stack-based DFS :"); + System.out.println("[#]\nRecursive Postorder DFS:"); + tree.dfsRecursivePostOrder(); + System.out.println(); + + + System.out.println("[#]\nStack-based DFS:"); tree.dfsStack(); + System.out.println(); - System.out.println("Using queue-based BFS :"); - tree.bfsQueue(); - System.out.println("Using post-order recursive DFS :"); - tree.dfsRecursivePostOrder(); + System.out.println("[#]\nQueue-based BFS:"); + tree.bfsQueue(); + System.out.println(); // Uncommenting the following 2 lines will result in an exception thrown because at least one Node of the Tree has more than 2 children and therefor a DFSRecursiveInorderBinary doesn't work. - System.out.println("Using in-order binary recursive DFS : (fail)"); - tree.dfsRecursiveInOrderBinary(); + //System.out.println("Using in-order binary recursive DFS : (fail)"); + //tree.dfsRecursiveInOrderBinary(); tree = new Tree(3, 2); - System.out.println("Using in-order binary recursive DFS : (succeed)"); + System.out.println("[#]\nRecursive Inorder DFS for Binary Tree:"); tree.dfsRecursiveInOrderBinary(); - - - System.out.println(""); + System.out.println(); } - } diff --git a/contents/tree_traversal/code/javascript/tree.js b/contents/tree_traversal/code/javascript/tree.js index 6670fe739..1fbffa02a 100644 --- a/contents/tree_traversal/code/javascript/tree.js +++ b/contents/tree_traversal/code/javascript/tree.js @@ -14,7 +14,7 @@ function dfsPreorder(tree) { return; } - console.log(tree.id); + process.stdout.write(tree.id + " "); tree.children.forEach(dfsPreorder); } @@ -24,7 +24,7 @@ function dfsPostorder(tree) { } tree.children.forEach(dfsPostorder); - console.log(tree.id); + process.stdout.write(tree.id + " "); } function dfsInorder(tree) { @@ -54,7 +54,7 @@ function dfsIterative(tree) { const stack = [tree]; while (stack.length > 0) { const current = stack.pop(); - console.log(current.id); + process.stdout.write(current.id + " "); stack.push(...current.children); } } @@ -63,13 +63,26 @@ function bfs(tree) { const queue = [tree]; while (queue.length > 0) { const current = queue.shift(); - console.log(current.id); + process.stdout.write(current.id + " "); queue.push(...current.children); } } -const root = createTree(3, 3); +const root = createTree(2, 3); +console.log("[#]\nRecursive DFS:"); dfsPreorder(root); +console.log(); +console.log("[#]\nRecursive Postorder DFS:"); dfsPostorder(root); +console.log(); +console.log("[#]\nStack-based DFS:"); dfsIterative(root); +console.log(); +console.log("[#]\nQueue-based BFS:"); bfs(root); +console.log(); +const root_binary = createTree(3, 2); +console.log("[#]\nRecursive Inorder DFS for Binary Tree:"); +dfsInorder(root_binary); +console.log(); + diff --git a/contents/tree_traversal/code/julia/Tree.jl b/contents/tree_traversal/code/julia/Tree.jl index d44345e8d..7382fdad0 100644 --- a/contents/tree_traversal/code/julia/Tree.jl +++ b/contents/tree_traversal/code/julia/Tree.jl @@ -1,4 +1,4 @@ -using DataStructures +using DataStructures, Printf struct Node children::Vector{Node} @@ -8,7 +8,7 @@ end function DFS_recursive(n::Node) # Here we are doing something... - println(n.ID) + print(n.ID, " ") for child in n.children DFS_recursive(child) @@ -22,7 +22,7 @@ function DFS_recursive_postorder(n::Node) end # Here we are doing something... - println(n.ID) + print(n.ID, " ") end # This assumes only 2 children, but accounts for other possibilities @@ -30,13 +30,13 @@ function DFS_recursive_inorder_btree(n::Node) if (length(n.children) == 2) DFS_recursive_inorder_btree(n.children[1]) - println(n.ID) + print(n.ID, " ") DFS_recursive_inorder_btree(n.children[2]) elseif (length(n.children) == 1) DFS_recursive_inorder_btree(n.children[1]) - println(n.ID) + print(n.ID, " ") elseif (length(n.children) == 0) - println(n.ID) + print(n.ID, " ") else println("Not a binary tree!") end @@ -47,7 +47,7 @@ function DFS_stack(n::Node) push!(s, n) while(length(s) > 0) - println(first(s).ID) + print(top(s).ID, " ") temp = pop!(s) for child in temp.children push!(s, child) @@ -60,7 +60,7 @@ function BFS_queue(n::Node) enqueue!(q, n) while(length(q) > 0) - println(first(q).ID) + print(first(q).ID, " ") temp = dequeue!(q) for child in temp.children enqueue!(q, child) @@ -84,26 +84,28 @@ function create_tree(num_row::Int64, num_child::Int64) end function main() - - println("Creating Tree") root = create_tree(2, 3) - println("Using recursive DFS:") + println("[#]\nRecursive DFS:") DFS_recursive(root); + println() - println("Using recursive DFS with post-order traversal:") + println("[#]\nRecursive Postorder DFS:") DFS_recursive_postorder(root); + println() - println("Using stack-based DFS:") + println("[#]\nStack-based DFS:") DFS_stack(root); + println() - println("Using queue-based BFS:") + println("[#]\nQueue-based BFS:") BFS_queue(root); + println() - println("Creating binary tree to test in-order traversal.") root_binary = create_tree(3,2) - println("Using In-order DFS:") + println("[#]\nRecursive Inorder DFS for Binary Tree:") DFS_recursive_inorder_btree(root_binary) + println() end main() diff --git a/contents/tree_traversal/code/php/tree_traversal.php b/contents/tree_traversal/code/php/tree_traversal.php index fde55046a..3c829977b 100644 --- a/contents/tree_traversal/code/php/tree_traversal.php +++ b/contents/tree_traversal/code/php/tree_traversal.php @@ -40,9 +40,7 @@ class TreeTraversal { public static function DFSRecursive(Tree $tree): void { - if ($tree->getId()) { - echo $tree->getId() . PHP_EOL; - } + echo $tree->getId() . ' '; foreach ($tree->getChildren() as $child) { static::DFSRecursive($child); } @@ -53,7 +51,7 @@ public static function DFSRecursivePostorder(Tree $tree): void foreach ($tree->getChildren() as $child) { static::DFSRecursivePostorder($child); } - echo $tree->getId() . PHP_EOL; + echo $tree->getId() . ' '; } public static function DFSRecursiveInorderBinary(Tree $tree): void @@ -61,15 +59,15 @@ public static function DFSRecursiveInorderBinary(Tree $tree): void switch (count($tree->getChildren())) { case 2: static::DFSRecursiveInorderBinary($tree->getChildren()[0]); - echo $tree->getId() . PHP_EOL; + echo $tree->getId() . ' '; static::DFSRecursiveInorderBinary($tree->getChildren()[1]); break; case 1: static::DFSRecursiveInorderBinary($tree->getChildren()[0]); - echo $tree->getId() . PHP_EOL; + echo $tree->getId() . ' '; break; case 0: - echo $tree->getId() . PHP_EOL; + echo $tree->getId() . ' '; break; default: throw new InvalidArgumentException('Not a binary tree!'); @@ -83,7 +81,7 @@ public static function DFSStack(Tree $tree): void $temp = null; while (null !== ($temp = array_pop($stack))) { - echo $temp->getId() . PHP_EOL; + echo $temp->getId() . ' '; foreach ($temp->getChildren() as $child) { $stack[] = $child; } @@ -96,7 +94,7 @@ public static function DFSQueue(Tree $tree): void $temp = null; while (null !== ($temp = array_shift($stack))) { - echo $temp->getId() . PHP_EOL; + echo $temp->getId() . ' '; foreach ($temp->getChildren() as $child) { $stack[] = $child; } @@ -104,16 +102,13 @@ public static function DFSQueue(Tree $tree): void } } -function generate_tree(int $numOfRows, int $numOfChildren, int $id = -1): Tree +function generate_tree(int $numOfRows, int $numOfChildren): Tree { - if ($id === -1) { - $id = 1; - } - $node = new Tree($id); + $node = new Tree($numOfRows); - if ($numOfRows > 1) { + if ($numOfRows > 0) { for ($i = 0; $i < $numOfChildren; $i++) { - $child = generate_tree($numOfRows - 1, $numOfChildren, $id * 10 + $i + 1); + $child = generate_tree($numOfRows - 1, $numOfChildren); $node->addChild($child); } } @@ -121,23 +116,28 @@ function generate_tree(int $numOfRows, int $numOfChildren, int $id = -1): Tree return $node; } -$node = generate_tree(3, 3); +$node = generate_tree(2, 3); -echo 'DFS Recursive:' . PHP_EOL; +echo '[#]' . PHP_EOL . 'Recursive DFS:' . PHP_EOL; TreeTraversal::DFSRecursive($node); +echo PHP_EOL; -echo 'DFS Recursive Postorder:' . PHP_EOL; +echo '[#]' . PHP_EOL . 'Recursive Postorder DFS:' . PHP_EOL; TreeTraversal::DFSRecursivePostorder($node); +echo PHP_EOL; -echo 'DFS Stack:' . PHP_EOL; +echo '[#]' . PHP_EOL . 'Stack-based DFS:' . PHP_EOL; TreeTraversal::DFSStack($node); +echo PHP_EOL; -echo 'DFS Queue:' . PHP_EOL; +echo '[#]' . PHP_EOL . 'Queue-based BFS:' . PHP_EOL; TreeTraversal::DFSQueue($node); +echo PHP_EOL; // If you want to try to run binary order on a non-binary tree, // comment out the generation of the new tree below. // If you do that, an exception will be thrown $node = generate_tree(3, 2); -echo 'DFS Recursive Inorder Binary:' . PHP_EOL; +echo '[#]' . PHP_EOL . 'Recursive Inorder DFS for Binary Tree:' . PHP_EOL; TreeTraversal::DFSRecursiveInorderBinary($node); +echo PHP_EOL; diff --git a/contents/tree_traversal/code/python/Tree_example.py b/contents/tree_traversal/code/python/Tree_example.py deleted file mode 100644 index 67dd516a3..000000000 --- a/contents/tree_traversal/code/python/Tree_example.py +++ /dev/null @@ -1,99 +0,0 @@ -class Node: - def __init__(self): - self.data = None - self.children = [] - - -def create_tree(node, num_row, num_child): - node.data = num_row - - if num_row > 0: - for i in range(num_child): - child = create_tree(Node(), num_row-1, num_child) - node.children.append(child) - - return node - - -def DFS_recursive(node): - if node.data != None: - print(node.data) - - for child in node.children: - DFS_recursive(child) - - -def DFS_recursive_postorder(node): - for child in node.children: - DFS_recursive_postorder(child) - - if node.data != None: - print(node.data) - - -# This assumes only 2 children, but accounts for other possibilities -def DFS_recursive_inorder_btree(node): - if (len(node.children) == 2): - DFS_recursive_inorder_btree(node.children[0]) - print(node.data) - DFS_recursive_inorder_btree(node.children[1]) - elif (len(node.children) == 1): - DFS_recursive_inorder_btree(node.children[0]) - print(node.data) - elif (len(node.children) == 0): - print(node.data) - else: - print("Not a binary tree!") - - -def DFS_stack(node): - stack = [] - stack.append(node) - - temp = None - - while len(stack) > 0: - print(stack[-1].data) - temp = stack.pop() - - for child in temp.children: - stack.append(child) - - -def BFS_queue(node): - queue = [] - queue.append(node) - - temp = None - - while len(queue) > 0: - print(queue[0].data) - temp = queue.pop(0) - - for child in temp.children: - queue.append(child) - - -def main(): - tree = create_tree(Node(), 3, 3) - - print("Recursive:") - DFS_recursive(tree) - - print("Recursive Postorder:") - DFS_recursive_postorder(tree) - - print("Stack:") - DFS_stack(tree) - - print("Queue:") - BFS_queue(tree) - - binaryTree = create_tree(Node(), 3, 2) - - print("Recursive Inorder Binary Tree:") - DFS_recursive_inorder_btree(binaryTree) - -if __name__ == '__main__': - main() - diff --git a/contents/tree_traversal/code/python/tree_traversal.py b/contents/tree_traversal/code/python/tree_traversal.py new file mode 100644 index 000000000..735837bdd --- /dev/null +++ b/contents/tree_traversal/code/python/tree_traversal.py @@ -0,0 +1,103 @@ +class Node: + def __init__(self): + self.data = None + self.children = [] + +def create_tree(node, num_row, num_child): + node.data = num_row + + if num_row > 0: + for i in range(num_child): + child = create_tree(Node(), num_row-1, num_child) + node.children.append(child) + + return node + + +def dfs_recursive(node): + if node.data != None: + print(node.data, end=' ') + + for child in node.children: + dfs_recursive(child) + + +def dfs_recursive_postorder(node): + for child in node.children: + dfs_recursive_postorder(child) + + if node.data != None: + print(node.data, end=' ') + + +# This assumes only 2 children, but accounts for other possibilities +def dfs_recursive_inorder_btree(node): + if len(node.children) == 2: + dfs_recursive_inorder_btree(node.children[0]) + print(node.data, end=' ') + dfs_recursive_inorder_btree(node.children[1]) + elif len(node.children) == 1: + dfs_recursive_inorder_btree(node.children[0]) + print(node.data, end=' ') + elif len(node.children) == 0: + print(node.data, end=' ') + else: + print("Not a binary tree!") + + +def dfs_stack(node): + stack = [] + stack.append(node) + + temp = None + + while len(stack) > 0: + print(stack[-1].data, end=' ') + temp = stack.pop() + + for child in temp.children: + stack.append(child) + + +def bfs_queue(node): + queue = [] + queue.append(node) + + temp = None + + while len(queue) > 0: + print(queue[0].data, end=' ') + temp = queue.pop(0) + + for child in temp.children: + queue.append(child) + + +def main(): + tree = create_tree(Node(), 2, 3) + + print("[#]\nRecursive DFS:") + dfs_recursive(tree) + print() + + print("[#]\nRecursive Postorder DFS:") + dfs_recursive_postorder(tree) + print() + + print("[#]\nStack-based DFS:") + dfs_stack(tree) + print() + + print("[#]\nQueue-based BFS:") + bfs_queue(tree) + print() + + binary_tree = create_tree(Node(), 3, 2) + + print("[#]\nRecursive Inorder DFS for Binary Tree:") + dfs_recursive_inorder_btree(binary_tree) + print() + +if __name__ == '__main__': + main() + diff --git a/contents/tree_traversal/code/rust/tree.rs b/contents/tree_traversal/code/rust/tree.rs index f281e1a8c..60e833858 100644 --- a/contents/tree_traversal/code/rust/tree.rs +++ b/contents/tree_traversal/code/rust/tree.rs @@ -7,7 +7,7 @@ struct Node { } fn dfs_recursive(n: &Node) { - println!("{}", n.value); + print!("{} ", n.value); for child in &n.children { dfs_recursive(child); @@ -19,22 +19,22 @@ fn dfs_recursive_postorder(n: &Node) { dfs_recursive_postorder(child); } - println!("{}", n.value); + print!("{} ", n.value); } fn dfs_recursive_inorder_btree(n: &Node) { match &n.children[..] { [left, right] => { dfs_recursive_inorder_btree(left); - println!("{}", n.value); + print!("{} ", n.value); dfs_recursive_inorder_btree(right); } [left] => { dfs_recursive_inorder_btree(left); - println!("{}", n.value); + print!("{} ", n.value); } - [] => println!("{}", n.value), - _ => println!("This is not a binary tree."), + [] => print!("{} ", n.value), + _ => print!("This is not a binary tree. "), } } @@ -42,7 +42,7 @@ fn dfs_stack(n: &Node) { let mut stack = vec![n]; while let Some(current) = stack.pop() { - println!("{}", current.value); + print!("{} ", current.value); stack.extend(¤t.children); } } @@ -52,7 +52,7 @@ fn bfs_queue(n: &Node) { queue.push_back(n); while let Some(current) = queue.pop_front() { - println!("{}", current.value); + print!("{} ", current.value); queue.extend(¤t.children); } } @@ -78,19 +78,24 @@ fn create_tree(num_row: u64, num_child: u64) -> Node { fn main() { let root = create_tree(2, 3); - println!("Recursive DFS:"); + println!("[#]\nRecursive DFS:"); dfs_recursive(&root); + println!(); - println!("Stack DFS:"); + println!("[#]\nRecursive Postorder DFS:"); + dfs_recursive_postorder(&root); + println!(); + + println!("[#]\nStack-based DFS:"); dfs_stack(&root); + println!(); - println!("Queue BFS:"); + println!("[#]\nQueue-based BFS:"); bfs_queue(&root); + println!(); - println!("Recursive post-order DFS:"); - dfs_recursive_postorder(&root); - - println!("Recursive in-order DFS BTree:"); + println!("[#]\nRecursive Inorder DFS for Binary Tree:"); let root_binary = create_tree(3, 2); dfs_recursive_inorder_btree(&root_binary); + println!(); } diff --git a/contents/tree_traversal/code/swift/tree.swift b/contents/tree_traversal/code/swift/tree.swift index e286c8fb0..ae64315ec 100644 --- a/contents/tree_traversal/code/swift/tree.swift +++ b/contents/tree_traversal/code/swift/tree.swift @@ -22,7 +22,7 @@ func createTree(numRows: Int, numChildren: Int) -> Node { } func dfsRecursive(node: Node) { - print(node.value) + print(node.value, terminator:" ") for child in node.children! { dfsRecursive(node: child) @@ -34,19 +34,19 @@ func dfsRecursivePostOrder(node: Node) { dfsRecursivePostOrder(node: child) } - print(node.value) + print(node.value, terminator:" ") } func dfsRecursiveInOrderBinary(node: Node) { if node.children?.count == 2 { dfsRecursiveInOrderBinary(node: node.children![0]) - print(node.value) + print(node.value, terminator:" ") dfsRecursiveInOrderBinary(node: node.children![1]) } else if node.children?.count == 1 { dfsRecursiveInOrderBinary(node: node.children![0]) - print(node.value) + print(node.value, terminator:" ") } else if node.children?.count == 0 { - print(node.value) + print(node.value, terminator:" ") } else { print("Not a binary tree!") } @@ -58,7 +58,7 @@ func dfsStack(node: Node) { while stack.count > 0 { temp = stack.popLast()! - print(temp.value) + print(temp.value, terminator:" ") for child in temp.children! { stack.append(child) @@ -72,7 +72,7 @@ func bfsQueue(node: Node) { while queue.count > 0 { temp = queue.remove(at: 0) - print(temp.value) + print(temp.value, terminator:" ") for child in temp.children! { queue.append(child) @@ -81,24 +81,29 @@ func bfsQueue(node: Node) { } func main() { - let root = createTree(numRows: 3, numChildren: 3) + let root = createTree(numRows: 2, numChildren: 3) - print("Using recursive DFS:") + print("[#]\nRecursive DFS:") dfsRecursive(node: root) + print() - print("Using recursive postorder DFS:") + print("[#]\nRecursive Postorder DFS:") dfsRecursivePostOrder(node: root) + print() - print("Using stack-based DFS:") + print("[#]\nStack-based DFS:") dfsStack(node: root) + print() - print("Using queue-based BFS:") + print("[#]\nQueue-based BFS:") bfsQueue(node: root) + print() let rootBinary = createTree(numRows: 3, numChildren: 2) - print("Using In-order DFS:") + print("[#]\nRecursive Inorder DFS for Binary Tree:") dfsRecursiveInOrderBinary(node: rootBinary) + print() } main() diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index 6d6504760..94b9086a8 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -17,7 +17,7 @@ Trees are naturally recursive data structures, and because of this, we cannot ac [import:1-10, lang:"javascript"](code/javascript/tree.js) As a note, a `node` struct is not necessary in javascript, so this is an example of how a tree might be constructed. {% sample lang="py" %} -[import:1-4, lang:"python"](code/python/Tree_example.py) +[import:1-4, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -64,7 +64,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="js" %} [import:12-19, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import:18-23, lang:"python"](code/python/Tree_example.py) +[import:17-22, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -72,11 +72,11 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="rs" %} [import:9-15 lang:"rust"](code/rust/tree.rs) {% sample lang="hs" %} -[import:6-7, lang:"haskell"](code/haskell/TreeTraversal.hs) +[import:7-8, lang:"haskell"](code/haskell/TreeTraversal.hs) {% sample lang="swift" %} [import:24-30, lang:"swift"](code/swift/tree.swift) {% sample lang="php" %} -[import:41-49, lang:"php"](code/php/tree_traversal.php) +[import:41-47, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:7-10, lang:"crystal"](code/crystal/tree-traversal.cr) {% sample lang="st" %} @@ -120,7 +120,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="js" %} [import:21-28, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import:26-31, lang:"python"](code/python/Tree_example.py) +[import:25-30, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -128,11 +128,11 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="rs" %} [import:17-24, lang:"rust"](code/rust/tree.rs) {% sample lang="hs" %} -[import:9-10, lang:"haskell"](code/haskell/TreeTraversal.hs) +[import:10-11, lang:"haskell"](code/haskell/TreeTraversal.hs) {% sample lang="swift" %} [import:32-38, lang:"swift"](code/swift/tree.swift) {% sample lang="php" %} -[import:51-57, lang:"php"](code/php/tree_traversal.php) +[import:49-55, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:12-15, lang:"crystal"](code/crystal/tree-traversal.cr) {% sample lang="st" %} @@ -148,7 +148,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="m" %} [import:47-62, lang:"matlab"](code/matlab/tree.m) {% sample lang="coco" %} -[import:11-15, lang:="coconut"](codo/coconut/tree_traversal.coco) +[import:11-15, lang:="coconut"](code/coconut/tree_traversal.coco) {% endmethod %}

@@ -171,7 +171,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="js" %} [import:30-51, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import:34-46, lang:"python"](code/python/Tree_example.py) +[import:34-45, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -179,11 +179,11 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="rs" %} [import:25-40, lang:"rust"](code/rust/tree.rs) {% sample lang="hs" %} -[import:12-16, lang:"haskell"](code/haskell/TreeTraversal.hs) +[import:13-17, lang:"haskell"](code/haskell/TreeTraversal.hs) {% sample lang="swift" %} [import:40-53, lang:"swift"](code/swift/tree.swift) {% sample lang="php" %} -[import:59-78, lang:"php"](code/php/tree_traversal.php) +[import:57-76, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:17-31, lang:"crystal"](code/crystal/tree-traversal.cr) {% sample lang="st" %} @@ -231,7 +231,7 @@ In code, it looks like this: {% sample lang="js" %} [import:53-60, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import:49-60, lang:"python"](code/python/Tree_example.py) +[import:48-59, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -239,11 +239,11 @@ In code, it looks like this: {% sample lang="rs" %} [import:41-48, lang:"rust"](code/rust/tree.rs) {% sample lang="hs" %} -[import:18-22, lang:"haskell"](code/haskell/TreeTraversal.hs) +[import:19-23, lang:"haskell"](code/haskell/TreeTraversal.hs) {% sample lang="swift" %} [import:55-67, lang:"swift"](code/swift/tree.swift) {% sample lang="php" %} -[import:80-91, lang:"php"](code/php/tree_traversal.php) +[import:78-89, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:33-41, lang:"crystal"](code/crystal/tree-traversal.cr) {% sample lang="st" %} @@ -284,7 +284,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="js" %} [import:62-69, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import:63-75, lang:"python"](code/python/Tree_example.py) +[import:62-72, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %}

@@ -292,11 +292,11 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="rs" %} [import:50-58, lang:"rust"](code/rust/tree.rs) {% sample lang="hs" %} -[import:24-28, lang:"haskell"](code/haskell/TreeTraversal.hs) +[import:25-29, lang:"haskell"](code/haskell/TreeTraversal.hs) {% sample lang="swift" %} [import:69-81, lang:"swift"](code/swift/tree.swift) {% sample lang="php" %} -[import:93-104, lang:"php"](code/php/tree_traversal.php) +[import:91-102, lang:"php"](code/php/tree_traversal.php) {% sample lang="crystal" %} [import:43-51, lang:"crystal"](code/crystal/tree-traversal.cr) {% sample lang="st" %} @@ -345,7 +345,7 @@ Here is a video describing tree traversal: {% sample lang="js" %} [import, lang:"javascript"](code/javascript/tree.js) {% sample lang="py" %} -[import, lang:"python"](code/python/Tree_example.py) +[import, lang:"python"](code/python/tree_traversal.py) {% sample lang="scratch" %} The code snippets were taken from this [Scratch project](https://scratch.mit.edu/projects/174017753/) From 83df0b9dbb32f5809b8aaf2c595455d62a556d39 Mon Sep 17 00:00:00 2001 From: James Schloss Date: Tue, 26 Oct 2021 17:07:58 +0200 Subject: [PATCH 060/146] Partial removal (#905) * removing partial implementations * removing languages completely --- contents/cooley_tukey/cooley_tukey.md | 6 --- .../verlet_integration/verlet_integration.md | 40 ------------------- 2 files changed, 46 deletions(-) diff --git a/contents/cooley_tukey/cooley_tukey.md b/contents/cooley_tukey/cooley_tukey.md index d67d4dbd2..67309b5d2 100644 --- a/contents/cooley_tukey/cooley_tukey.md +++ b/contents/cooley_tukey/cooley_tukey.md @@ -81,8 +81,6 @@ For some reason, though, putting code to this transformation really helped me fi [import:7-13, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} [import:6-12, lang:"python"](code/python/fft.py) -{% sample lang="scratch" %} -[import:4-13, lang:"julia"](code/julia/fft.jl) {% sample lang="asm-x64" %} [import:15-74, lang:"asm-x64"](code/asm-x64/fft.s) {% sample lang="js" %} @@ -136,8 +134,6 @@ In the end, the code looks like: [import:15-28, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} [import:15-26, lang:"python"](code/python/fft.py) -{% sample lang="scratch" %} -[import:16-32, lang:"julia"](code/julia/fft.jl) {% sample lang="asm-x64" %} [import:76-165, lang:"asm-x64"](code/asm-x64/fft.s) {% sample lang="js" %} @@ -251,8 +247,6 @@ Note: I implemented this in Julia because the code seems more straightforward in [import, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} [import, lang:"python"](code/python/fft.py) -{% sample lang="scratch" %} -Some rather impressive scratch code was submitted by Jie and can be found here: https://scratch.mit.edu/projects/37759604/#editor {% sample lang="asm-x64" %} [import, lang:"asm-x64"](code/asm-x64/fft.s) {% sample lang="js" %} diff --git a/contents/verlet_integration/verlet_integration.md b/contents/verlet_integration/verlet_integration.md index 402a7ba1b..08fe4a4b3 100644 --- a/contents/verlet_integration/verlet_integration.md +++ b/contents/verlet_integration/verlet_integration.md @@ -42,15 +42,6 @@ Here is what it looks like in code: [import:1-10, lang:"python"](code/python/verlet.py) {% sample lang="hs" %} [import:14-21, lang:"haskell"](code/haskell/verlet.hs) -{% sample lang="scratch" %} -Unfortunately, this has not yet been implemented in scratch, so here's Julia code: -[import:1-13, lang:"julia"](code/julia/verlet.jl) -{% sample lang="m" %} -Unfortunately, this has not yet been implemented in matlab, so here's Julia code: -[import:1-13, lang:"julia"](code/julia/verlet.jl) -{% sample lang="LabVIEW" %} -Unfortunately, this has not yet been implemented in LabVIEW, so here's Julia code: -[import:1-13, lang:"julia"](code/julia/verlet.jl) {% sample lang="js" %} [import:1-14, lang:"javascript"](code/javascript/verlet.js) {% sample lang="rs" %} @@ -100,15 +91,6 @@ However, the error for this is $$\mathcal{O}(\Delta t)$$, which is quite poor, b [import:12-23, lang:"python"](code/python/verlet.py) {% sample lang="hs" %} [import:23-28, lang:"haskell"](code/haskell/verlet.hs) -{% sample lang="scratch" %} -Unfortunately, this has not yet been implemented in scratch, so here's Julia code: -[import:15-31, lang:"julia"](code/julia/verlet.jl) -{% sample lang="m" %} -Unfortunately, this has not yet been implemented in matlab, so here's Julia code: -[import:15-31, lang:"julia"](code/julia/verlet.jl) -{% sample lang="LabVIEW" %} -Unfortunately, this has not yet been implemented in LabVIEW, so here's Julia code: -[import:15-31, lang:"julia"](code/julia/verlet.jl) {% sample lang="js" %} [import:16-32, lang:"javascript"](code/javascript/verlet.js) {% sample lang="rs" %} @@ -172,15 +154,6 @@ Here is the velocity Verlet method in code: [import:25-34, lang:"python"](code/python/verlet.py) {% sample lang="hs" %} [import:30-35, lang:"haskell"](code/haskell/verlet.hs) -{% sample lang="scratch" %} -Unfortunately, this has not yet been implemented in scratch, so here's Julia code: -[import:33-45, lang:"julia"](code/julia/verlet.jl) -{% sample lang="m" %} -Unfortunately, this has not yet been implemented in matlab, so here's Julia code: -[import:33-45, lang:"julia"](code/julia/verlet.jl) -{% sample lang="LabVIEW" %} -Unfortunately, this has not yet been implemented in LabVIEW, so here's Julia code: -[import:33-45, lang:"julia"](code/julia/verlet.jl) {% sample lang="js" %} [import:34-45, lang:"javascript"](code/javascript/verlet.js) {% sample lang="rs" %} @@ -230,19 +203,6 @@ Both of these methods work simply by iterating timestep-by-timestep and can be w [import, lang:"python"](code/python/verlet.py) {% sample lang="hs" %} [import, lang:"haskell"](code/haskell/verlet.hs) -{% sample lang="scratch" %} -Submitted by Jie -

- -

-Link: [https://scratch.mit.edu/projects/173039394/](https://scratch.mit.edu/projects/173039394/) -{% sample lang="m" %} -[import, lang:"matlab"](code/matlab/verlet.m) -{% sample lang="LabVIEW" %} -Submitted by P. Mekhail -

- -

{% sample lang="js" %} [import, lang:"javascript"](code/javascript/verlet.js) {% sample lang="rs" %} From cfcfccccc95484aa19d76397f6788e3f7c7fca9a Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Tue, 26 Oct 2021 17:45:54 +0200 Subject: [PATCH 061/146] Added SCons compilation instructions (#885) * Added C compilation to SCons (not all work, though) * First fully functional version of the build system for C code * Simplified SConstruct file * Simplified SConscript files SConscript files are now mostly universal for C programs. Additionally, the build hierarchy is now flattened (executables under the language folder) * fixing chapter to use split-op code (#888) Removed the quantum_systems SConscript * modified Dockerfile for ntindle * Changed my name in CONTRIBUTORS.md * apparently forgot an algorithm Co-authored-by: James Schloss --- .devcontainer/Dockerfile | 5 +++-- .gitignore | 7 +++++++ CONTRIBUTORS.md | 2 +- SConscript | 10 ++++++++++ SConstruct | 20 +++++++++++++++++++ contents/IFS/code/c/SConscript | 6 ++++++ .../approximate_counting/code/c/SConscript | 6 ++++++ contents/barnsley/code/c/SConscript | 6 ++++++ contents/computus/code/c/SConscript | 6 ++++++ contents/cooley_tukey/code/c/SConscript | 6 ++++++ .../euclidean_algorithm/code/c/SConscript | 6 ++++++ contents/flood_fill/code/c/SConscript | 6 ++++++ .../forward_euler_method/code/c/SConscript | 6 ++++++ .../gaussian_elimination/code/c/SConscript | 6 ++++++ contents/graham_scan/code/c/SConscript | 6 ++++++ contents/huffman_encoding/code/c/SConscript | 6 ++++++ contents/jarvis_march/code/c/SConscript | 6 ++++++ .../monte_carlo_integration/code/c/SConscript | 6 ++++++ .../split-operator_method/code/c/SConscript | 6 ++++++ .../stable_marriage_problem/code/c/SConscript | 6 ++++++ contents/thomas_algorithm/code/c/SConscript | 6 ++++++ contents/tree_traversal/code/c/SConscript | 6 ++++++ contents/verlet_integration/code/c/SConscript | 6 ++++++ 23 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 SConscript create mode 100644 SConstruct create mode 100644 contents/IFS/code/c/SConscript create mode 100644 contents/approximate_counting/code/c/SConscript create mode 100644 contents/barnsley/code/c/SConscript create mode 100644 contents/computus/code/c/SConscript create mode 100644 contents/cooley_tukey/code/c/SConscript create mode 100644 contents/euclidean_algorithm/code/c/SConscript create mode 100644 contents/flood_fill/code/c/SConscript create mode 100644 contents/forward_euler_method/code/c/SConscript create mode 100644 contents/gaussian_elimination/code/c/SConscript create mode 100644 contents/graham_scan/code/c/SConscript create mode 100644 contents/huffman_encoding/code/c/SConscript create mode 100644 contents/jarvis_march/code/c/SConscript create mode 100644 contents/monte_carlo_integration/code/c/SConscript create mode 100644 contents/split-operator_method/code/c/SConscript create mode 100644 contents/stable_marriage_problem/code/c/SConscript create mode 100644 contents/thomas_algorithm/code/c/SConscript create mode 100644 contents/tree_traversal/code/c/SConscript create mode 100644 contents/verlet_integration/code/c/SConscript diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 18af4df12..aec4ab153 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,7 +6,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} # [Optional] Uncomment this section to install additional OS packages. RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk rustc libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch + && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk rustc libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch libfftw3-dev # Setup Crystal RUN echo 'deb http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_20.04/ /' | sudo tee /etc/apt/sources.list.d/devel:languages:crystal.list @@ -98,6 +98,7 @@ ENV PATH=$PATH:~/swift/usr/bin RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket -RUN pip install wheel matplotlib numpy coconut +RUN pip install wheel matplotlib numpy coconut scons RUN sudo sh -c 'npm install -g typescript' + diff --git a/.gitignore b/.gitignore index db26e0ad0..231da8ea1 100644 --- a/.gitignore +++ b/.gitignore @@ -517,3 +517,10 @@ vscode/ # aspell *.bak + +# SCons intermidiate files +.sconsign.dblite +*.o + +# SCons build directory +build/ diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9b2c1b460..82f3c173a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -51,7 +51,7 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Vincent Zalzal - Jonathan D B Van Schenck - James Goytia -- Amaras +- Sammy Plat - Jonathan Dönszelmann - Ishaan Verma - Delphi1024 diff --git a/SConscript b/SConscript new file mode 100644 index 000000000..be18b33d3 --- /dev/null +++ b/SConscript @@ -0,0 +1,10 @@ +from pathlib import Path + +Import('*') + +for p in Path('contents').iterdir(): + if (q := (p / 'code')).exists(): + for path in q.iterdir(): + if path.stem in languages: + env.SConscript(path / 'SConscript', exports='env', + must_exist=0) diff --git a/SConstruct b/SConstruct new file mode 100644 index 000000000..df000f732 --- /dev/null +++ b/SConstruct @@ -0,0 +1,20 @@ +""" +SCons top-level build description (SConstruct) for the Arcane Algorithm Achive + +This provides Builder objects for each of the language implementations in the AAA; however, this work cannot be considered exhaustive until every language has been covered. + +Currently, the aim is to provide a way to compile or copy the implementation files to the build directory, as well as to provide ways to run them and capture their output. + +To run the compilation for all implmeentations in one language, e.g. Rust, run the command `scons build/c`, and the resulting executables will be available in the `cuild/c` directory, each in their respective algorithm directory, containing the executable.""" + +from pathlib import Path + +env = Environment() + +# Add other languages here when you want to add language targets +languages = ['c'] + +env.C = env.Program + +SConscript('SConscript', exports='env languages') + diff --git a/contents/IFS/code/c/SConscript b/contents/IFS/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/IFS/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/approximate_counting/code/c/SConscript b/contents/approximate_counting/code/c/SConscript new file mode 100644 index 000000000..34a951e7f --- /dev/null +++ b/contents/approximate_counting/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m') diff --git a/contents/barnsley/code/c/SConscript b/contents/barnsley/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/barnsley/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/computus/code/c/SConscript b/contents/computus/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/computus/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/cooley_tukey/code/c/SConscript b/contents/cooley_tukey/code/c/SConscript new file mode 100644 index 000000000..2cd13de37 --- /dev/null +++ b/contents/cooley_tukey/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS=['m', 'fftw3']) diff --git a/contents/euclidean_algorithm/code/c/SConscript b/contents/euclidean_algorithm/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/euclidean_algorithm/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/flood_fill/code/c/SConscript b/contents/flood_fill/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/flood_fill/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/forward_euler_method/code/c/SConscript b/contents/forward_euler_method/code/c/SConscript new file mode 100644 index 000000000..34a951e7f --- /dev/null +++ b/contents/forward_euler_method/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m') diff --git a/contents/gaussian_elimination/code/c/SConscript b/contents/gaussian_elimination/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/gaussian_elimination/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/graham_scan/code/c/SConscript b/contents/graham_scan/code/c/SConscript new file mode 100644 index 000000000..34a951e7f --- /dev/null +++ b/contents/graham_scan/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS='m') diff --git a/contents/huffman_encoding/code/c/SConscript b/contents/huffman_encoding/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/huffman_encoding/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/jarvis_march/code/c/SConscript b/contents/jarvis_march/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/jarvis_march/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/monte_carlo_integration/code/c/SConscript b/contents/monte_carlo_integration/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/monte_carlo_integration/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/split-operator_method/code/c/SConscript b/contents/split-operator_method/code/c/SConscript new file mode 100644 index 000000000..2cd13de37 --- /dev/null +++ b/contents/split-operator_method/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c'), LIBS=['m', 'fftw3']) diff --git a/contents/stable_marriage_problem/code/c/SConscript b/contents/stable_marriage_problem/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/stable_marriage_problem/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/thomas_algorithm/code/c/SConscript b/contents/thomas_algorithm/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/thomas_algorithm/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/tree_traversal/code/c/SConscript b/contents/tree_traversal/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/tree_traversal/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/verlet_integration/code/c/SConscript b/contents/verlet_integration/code/c/SConscript new file mode 100644 index 000000000..fd696f9ce --- /dev/null +++ b/contents/verlet_integration/code/c/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.C(f'#/build/c/{dirname}', Glob('*.c')) From 4a81890603b389e5f281d8159e4cc441093859f8 Mon Sep 17 00:00:00 2001 From: Henrik Christensen Date: Tue, 26 Oct 2021 18:19:52 +0200 Subject: [PATCH 062/146] c# tree traversal: fixed index out of range issue (#894) --- .../tree_traversal/code/csharp/Program.cs | 1 - contents/tree_traversal/code/csharp/Tree.cs | 34 +++++++++++-------- contents/tree_traversal/tree_traversal.md | 12 +++---- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/contents/tree_traversal/code/csharp/Program.cs b/contents/tree_traversal/code/csharp/Program.cs index 4308794dd..0fc35c547 100644 --- a/contents/tree_traversal/code/csharp/Program.cs +++ b/contents/tree_traversal/code/csharp/Program.cs @@ -1,4 +1,3 @@ -// submitted by Julian Schacher (jspp) using System; namespace TreeTraversal diff --git a/contents/tree_traversal/code/csharp/Tree.cs b/contents/tree_traversal/code/csharp/Tree.cs index f581008d7..28df47c91 100644 --- a/contents/tree_traversal/code/csharp/Tree.cs +++ b/contents/tree_traversal/code/csharp/Tree.cs @@ -1,4 +1,3 @@ -// submitted by Julian Schacher (jspp) using System; using System.Collections.Generic; @@ -11,23 +10,23 @@ public class Tree public Tree(int depthCount, int childrenCount) { - this.Id = depthCount; + Id = 1; if (depthCount > 0) { for (int i = 0; i < childrenCount; i++) - this._children.Add(new Tree(depthCount - 1, childrenCount)); + _children.Add(new Tree(Id * 10 + i + 1, depthCount - 1, childrenCount)); } } private Tree(int id, int depthCount, int childrenCount) { - this.Id = id; + Id = id; if (!(depthCount <= 1)) { for (int i = 0; i < childrenCount; i++) - this._children.Add(new Tree(this.Id * 10 + i + 1, depthCount - 1, childrenCount)); + _children.Add(new Tree(Id * 10 + i + 1, depthCount - 1, childrenCount)); } } @@ -61,20 +60,25 @@ public void DFSRecursiveInorderBinary() { DFSRecursiveInorderBinary(this); - // This assumes only 2 children void DFSRecursiveInorderBinary(Tree tree) { - if (tree._children.Count > 2) - throw new Exception("Not binary tree!"); - - if (tree._children.Count > 0) + switch (tree._children.Count) { - DFSRecursiveInorderBinary(tree._children[0]); - Console.Write(tree.Id + " "); - DFSRecursiveInorderBinary(tree._children[1]); + case 2: + DFSRecursiveInorderBinary(tree._children[0]); + Console.Write(tree.Id + " "); + DFSRecursiveInorderBinary(tree._children[1]); + break; + case 1: + DFSRecursiveInorderBinary(tree._children[0]); + Console.Write(tree.Id + " "); + break; + case 0: + Console.Write(tree.Id + " "); + break; + default: + throw new Exception("Not binary tree!"); } - else - Console.Write(tree.Id + " "); } } diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index 94b9086a8..4b6c5b762 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -8,7 +8,7 @@ Trees are naturally recursive data structures, and because of this, we cannot ac {% sample lang="cpp" %} [import:12-15, lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:7-11, lang:"csharp"](code/csharp/Tree.cs) +[import:6-10, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:7-11, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} @@ -56,7 +56,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="cpp" %} [import:17-24, lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:34-45, lang:"csharp"](code/csharp/Tree.cs) +[import:33-44, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:37-45, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} @@ -112,7 +112,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="cpp" %} [import:26-31, lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:47-58, lang:"csharp"](code/csharp/Tree.cs) +[import:46-57, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:47-53, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} @@ -163,7 +163,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="cpp" %} [import:34-52 lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:60-79, lang:"csharp"](code/csharp/Tree.cs) +[import:59-83, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:55-73, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} @@ -223,7 +223,7 @@ In code, it looks like this: {% sample lang="cpp" %} [import:55-70, lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:81-94, lang:"csharp"](code/csharp/Tree.cs) +[import:85-98, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:75-93, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} @@ -276,7 +276,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="cpp" %} [import:73-86, lang:"cpp"](code/c++/tree_example.cpp) {% sample lang="cs" %} -[import:96-109, lang:"csharp"](code/csharp/Tree.cs) +[import:100-113, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} [import:95-113, lang:"c"](code/c/tree_traversal.c) {% sample lang="java" %} From 91410d7ce05a6c0f673acbc72ca4c4bd08b392cb Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Tue, 2 Nov 2021 20:40:59 +0100 Subject: [PATCH 063/146] Add devcontainer setup for V lang --- .devcontainer/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 18af4df12..34299941f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -91,8 +91,9 @@ ENV PATH=$PATH:~/swift/usr/bin ## https://github.com/elm/compiler/blob/master/installers/linux/README.md # Setup V -## https://github.com/vlang/v/blob/master/doc/docs.md - +RUN mkdir -p ~/vlang && wget https://github.com/vlang/v/releases/download/weekly.2021.44/v_linux.zip -O ~/vlang/vlang.zip && \ + unzip ~/vlang/vlang.zip -d ~/vlang +ENV PATH=$PATH:~/vlang/v # Install the packages that needed extra help RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ From 3a75d02df481f5d7f973f06b4ffb514acb5b7880 Mon Sep 17 00:00:00 2001 From: Eric Berquist Date: Wed, 3 Nov 2021 11:26:34 -0400 Subject: [PATCH 064/146] Change Racket lang include from lisp to racket (#884) Co-authored-by: James Schloss --- contents/euclidean_algorithm/euclidean_algorithm.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contents/euclidean_algorithm/euclidean_algorithm.md b/contents/euclidean_algorithm/euclidean_algorithm.md index 82aa64a2a..f44c3acb7 100644 --- a/contents/euclidean_algorithm/euclidean_algorithm.md +++ b/contents/euclidean_algorithm/euclidean_algorithm.md @@ -56,7 +56,7 @@ The algorithm is a simple way to find the *greatest common divisor* (GCD) of two {% sample lang="scala" %} [import:3-8, lang="scala"](code/scala/euclidean.scala) {% sample lang="racket" %} -[import:3-14, lang="lisp"](code/racket/euclidean_algorithm.rkt) +[import:3-14, lang="racket"](code/racket/euclidean_algorithm.rkt) {% sample lang="ruby" %} [import:8-19, lang="ruby"](code/ruby/euclidean.rb) {% sample lang="st" %} @@ -146,7 +146,7 @@ Modern implementations, though, often use the modulus operator (%) like so {% sample lang="scala" %} [import:10-14, lang="scala"](code/scala/euclidean.scala) {% sample lang="racket" %} -[import:16-24, lang="lisp"](code/racket/euclidean_algorithm.rkt) +[import:16-24, lang="racket"](code/racket/euclidean_algorithm.rkt) {% sample lang="ruby" %} [import:1-6, lang="ruby"](code/ruby/euclidean.rb) {% sample lang="st" %} @@ -252,7 +252,7 @@ and modulo method: {% sample lang="scala" %} [import, lang="scala"](code/scala/euclidean.scala) {% sample lang="racket" %} -[import, lang="lisp"](code/racket/euclidean_algorithm.rkt) +[import, lang="racket"](code/racket/euclidean_algorithm.rkt) {% sample lang="ruby" %} [import, lang="ruby"](code/ruby/euclidean.rb) {% sample lang="st" %} From 174c4975ae1a244424b08b547e290345dd22b409 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Wed, 3 Nov 2021 19:46:39 +0100 Subject: [PATCH 065/146] Add devcontainer setup for VimL/Vim script (#912) --- .devcontainer/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index eff8fd4da..ee273e5af 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -82,7 +82,8 @@ RUN mkdir -p ~/swift && wget https://swift.org/builds/swift-5.5-release/ubuntu20 ENV PATH=$PATH:~/swift/usr/bin # Setup viml -## ? +# To run vim script commands use `/usr/bin/vim -c ":source %" ` +RUN export DEBIAN_FRONTEND=noninteractive && apt-get -y install --no-install-recommends vim # Setup whitespace ## ? From a3825b250d3eb0cab952af097b944361a777e0f4 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sun, 7 Nov 2021 15:49:28 +0100 Subject: [PATCH 066/146] Add devcontainer setup for Elm and fix Euler Elm example (#911) --- .devcontainer/Dockerfile | 4 +- .../code/elm/elm-package.json | 20 - .../forward_euler_method/code/elm/elm.json | 28 ++ .../forward_euler_method/code/elm/euler.elm | 332 --------------- .../code/elm/src/Euler.elm | 397 ++++++++++++++++++ .../forward_euler_method.md | 6 +- 6 files changed, 431 insertions(+), 356 deletions(-) delete mode 100644 contents/forward_euler_method/code/elm/elm-package.json create mode 100644 contents/forward_euler_method/code/elm/elm.json delete mode 100644 contents/forward_euler_method/code/elm/euler.elm create mode 100644 contents/forward_euler_method/code/elm/src/Euler.elm diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ee273e5af..695b0ffbf 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -89,7 +89,9 @@ RUN export DEBIAN_FRONTEND=noninteractive && apt-get -y install --no-install-rec ## ? # Setup Elm -## https://github.com/elm/compiler/blob/master/installers/linux/README.md +RUN mkdir -p ~/elm && curl -L -o ~/elm/elm.gz https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz && \ + gunzip ~/elm/elm.gz && chmod +x ~/elm/elm +ENV PATH=$PATH:~/elm # Setup V RUN mkdir -p ~/vlang && wget https://github.com/vlang/v/releases/download/weekly.2021.44/v_linux.zip -O ~/vlang/vlang.zip && \ diff --git a/contents/forward_euler_method/code/elm/elm-package.json b/contents/forward_euler_method/code/elm/elm-package.json deleted file mode 100644 index fccb4595b..000000000 --- a/contents/forward_euler_method/code/elm/elm-package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "1.0.0", - "summary": "helpful summary of your project, less than 80 characters", - "repository": "https://github.com/user/project.git", - "license": "BSD3", - "source-directories": [ - "." - ], - "exposed-modules": [], - "dependencies": { - "CallumJHays/elm-sliders": "1.0.1 <= v < 2.0.0", - "elm-lang/core": "5.1.1 <= v < 6.0.0", - "elm-lang/html": "2.0.0 <= v < 3.0.0", - "elm-lang/mouse": "1.0.1 <= v < 2.0.0", - "elm-lang/svg": "2.0.0 <= v < 3.0.0", - "elm-lang/window": "1.0.1 <= v < 2.0.0", - "rtfeldman/hex": "1.0.0 <= v < 2.0.0" - }, - "elm-version": "0.18.0 <= v < 0.19.0" -} diff --git a/contents/forward_euler_method/code/elm/elm.json b/contents/forward_euler_method/code/elm/elm.json new file mode 100644 index 000000000..5eac761dd --- /dev/null +++ b/contents/forward_euler_method/code/elm/elm.json @@ -0,0 +1,28 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "bemyak/elm-slider": "1.0.0", + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/json": "1.1.3", + "elm/svg": "1.0.1", + "elm/time": "1.0.0", + "rtfeldman/elm-hex": "1.0.0" + }, + "indirect": { + "debois/elm-dom": "1.3.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/contents/forward_euler_method/code/elm/euler.elm b/contents/forward_euler_method/code/elm/euler.elm deleted file mode 100644 index a8d8d3c89..000000000 --- a/contents/forward_euler_method/code/elm/euler.elm +++ /dev/null @@ -1,332 +0,0 @@ -module Euler exposing (..) - -import Html exposing (Html, div, button, text, h3) -import Html.Attributes exposing (style) -import Html.Events exposing (onClick, on) -import Time exposing (Time, second) -import Maybe exposing (withDefault) -import Window exposing (Size, size) -import Svg exposing (svg, circle, line, polyline) -import Svg.Attributes exposing (width, height, stroke, x1, x2, y1, y2, cx, cy, r, points, fill) -import Task exposing (perform) -import Slider exposing (..) -import Mouse -import Json.Decode as Decode -import Hex - - -main = - Html.program - { init = init - , view = view - , update = update - , subscriptions = subscriptions - } - - - --- MODEL - - -type alias Model = - { part : Particle - , dt : Time - , dt0 : Time - , t : Time - , status : Status - , wWidth : Int - , wHeight : Int - , history : List ( Time, Time, Particle ) - , drag : Maybe Drag - } - - -type alias Position = - Float - - -type alias Velocity = - Float - - -type alias Particle = - { pos : List Position, vel : List Velocity } - - -type Status - = Idle - | Running - - -type alias Drag = - { start : Position - , current : Position - } - - -getX : Particle -> Position -getX p = - withDefault 0 <| List.head <| .pos p - - -getV : Particle -> Velocity -getV p = - withDefault 0 <| List.head <| .vel p - - -getX0 : Model -> Position -getX0 m = - let - scale x = - 3 - 6 * x / (toFloat m.wHeight) - in - case m.drag of - Nothing -> - getX m.part - - Just { start, current } -> - getX m.part + scale current - scale start - - - --- INIT - - -init : ( Model, Cmd Msg ) -init = - ( Model (Particle [ x0 ] [ 0 ]) 0.5 0.5 0 Idle 0 0 [] Nothing, perform GetSize size ) - - -x0 : Position -x0 = - 2.5 - - - --- UPDATE - - -type Msg - = Start - | Stop - | Tick Time - | GetSize Size - | SliderUpdate Float - | DragStart Mouse.Position - | DragAt Mouse.Position - | DragEnd Mouse.Position - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - Start -> - ( { model - | status = Running - , t = 0 - , dt = model.dt0 - , drag = Nothing - } - , Cmd.none - ) - - Stop -> - ( { model - | status = Idle - , part = Particle [ x0 ] [ 0 ] - , t = 0 - } - , Cmd.none - ) - - Tick _ -> - case model.status of - Idle -> - ( model, Cmd.none ) - - Running -> - if model.t > 5 + model.dt then - ( { model - | status = Idle - , part = Particle [ x0 ] [ 0 ] - , history = ( model.dt, model.t, model.part ) :: model.history - , t = 0 - } - , Cmd.none - ) - else - ( { model - | part = evolve model.part model.t model.dt - , t = model.t + model.dt - } - , perform GetSize size - ) - - GetSize s -> - ( { model | wWidth = s.width, wHeight = s.height * 8 // 10 }, Cmd.none ) - - SliderUpdate dt -> - ( { model | dt0 = dt }, Cmd.none ) - - DragStart { x, y } -> - case model.status of - Idle -> - ( { model | drag = Just (Drag (toFloat y) (toFloat y)) }, Cmd.none ) - - Running -> - ( model, Cmd.none ) - - DragAt { x, y } -> - ( { model | drag = Maybe.map (\{ start } -> Drag start (toFloat y)) model.drag } - , Cmd.none - ) - - DragEnd _ -> - ( { model - | drag = Nothing - , part = Particle [ getX0 model ] [ k * getX0 model ] - } - , Cmd.none - ) - - -k : Float -k = - -2 - - -diffEq : Position -> Velocity -> Time -> Time -> ( Position, Velocity ) -diffEq x v t dt = - ( x + (k * x) * dt, k * (x + (k * x) * dt) ) - - -evolve : Particle -> Time -> Time -> Particle -evolve p t dt = - let - ( x, v ) = - diffEq (getX p) (getV p) t dt - in - { p | pos = x :: p.pos, vel = v :: p.vel } - - - --- SUBSCRIPTIONS - - -subscriptions : Model -> Sub Msg -subscriptions model = - case model.drag of - Nothing -> - Time.every (model.dt * second) Tick - - Just _ -> - Sub.batch [ Mouse.moves DragAt, Mouse.ups DragEnd ] - - - --- VIEW - - -view : Model -> Html Msg -view model = - div [] - [ h3 [] [ text "Drag the ball up or down, pick a dt and click Start" ] - , h3 [ style [ ( "color", gradient model.dt0 ) ] ] - [ viewSlider - , text ("dt = " ++ toString model.dt0) - , button [ onClick Start ] [ text "Start" ] - , button [ onClick Stop ] [ text "Stop" ] - ] - , svg - [ width (toString model.wWidth) - , height (toString model.wHeight) - , stroke "black" - ] - ([ line - [ x1 "0" - , x2 (toString model.wWidth) - , y1 (toString (model.wHeight // 2)) - , y2 (toString (model.wHeight // 2)) - ] - [] - , line - [ x1 (toString (model.wWidth // 20)) - , x2 (toString (model.wWidth // 20)) - , y1 "0" - , y2 (toString model.wHeight) - ] - [] - , viewCircle model - ] - ++ (plotHistory model) - ) - ] - - -viewSlider : Html Msg -viewSlider = - props2view [ MinVal 0, MaxVal 1, Step 0.01, onChange SliderUpdate ] - - -scaleX : Int -> Position -> String -scaleX h x = - toString (toFloat h / 2 * (1 - x / 3)) - - -scaleT : Int -> Time -> String -scaleT w t = - toString (toFloat w * (0.05 + t / 5)) - - -viewCircle : Model -> Html Msg -viewCircle m = - circle - [ cy (scaleX m.wHeight (getX0 m)) - , cx (scaleT m.wWidth m.t) - , r "10" - , on "mousedown" (Decode.map DragStart Mouse.position) - ] - [] - - -plotPath : Int -> Int -> ( Time, Time, Particle ) -> String -plotPath w h ( dt, tf, particle ) = - let - comb x ( t, s ) = - ( t - dt, s ++ (scaleT w t) ++ "," ++ (scaleX h x) ++ " " ) - in - Tuple.second <| List.foldl comb ( tf, "" ) particle.pos - - -plotHistory : Model -> List (Html Msg) -plotHistory m = - let - ( w, h ) = - ( m.wWidth, m.wHeight ) - in - List.map - (\( dt, t, p ) -> - polyline - [ stroke "black" - , fill "none" - , stroke (gradient dt) - , points (plotPath w h ( dt, t, p )) - ] - [] - ) - (( m.dt, m.t, m.part ) :: m.history) - - -gradient : Time -> String -gradient dt = - let - ( r, g, b ) = - ( round (255 * dt), 0, round (255 * (1 - dt)) ) - - col = - Hex.toString (256 * (256 * r + g) + b) - in - if String.length col < 6 then - "#" ++ String.repeat (6 - String.length col) "0" ++ col - else - "#" ++ col diff --git a/contents/forward_euler_method/code/elm/src/Euler.elm b/contents/forward_euler_method/code/elm/src/Euler.elm new file mode 100644 index 000000000..c9207d2de --- /dev/null +++ b/contents/forward_euler_method/code/elm/src/Euler.elm @@ -0,0 +1,397 @@ +module Euler exposing (..) + +import Browser +import Browser.Dom exposing (Viewport) +import Browser.Events as Events +import Hex +import Html exposing (Html, button, div, h3, text) +import Html.Attributes exposing (style) +import Html.Events exposing (on, onClick) +import Json.Decode as Decode exposing (Decoder) +import Maybe +import SingleSlider as Slider +import Svg exposing (circle, line, polyline, svg) +import Svg.Attributes exposing (cx, cy, fill, height, points, r, stroke, width, x1, x2, y1, y2) +import Task +import Time exposing (Posix) + + +main : Platform.Program () Model Msg +main = + Browser.element + { init = \() -> init + , view = view + , update = update + , subscriptions = subscriptions + } + + + +-- MODEL + + +type alias Model = + { part : Particle + , dt : Time + , dt0 : Time + , t : Time + , status : Status + , wWidth : Float + , wHeight : Float + , history : List ( Time, Time, Particle ) + , drag : Maybe Drag + , slider : Slider.Model + } + + +x0 : Position +x0 = + 2.5 + + +init : ( Model, Cmd Msg ) +init = + ( { part = Particle [ x0 ] [ 0 ] + , dt = 0.25 + , dt0 = 0.25 + , t = 0 + , status = Idle + , wWidth = 0 + , wHeight = 0 + , history = [] + , drag = Nothing + , slider = + { min = 0 + , max = 1 + , step = 0.01 + , value = 0.25 + , minFormatter = \_ -> "" + , maxFormatter = \_ -> "" + , currentValueFormatter = \_ _ -> "" + , disabled = False + } + } + , Task.perform GetViewPort Browser.Dom.getViewport + ) + + +type alias Time = + Float + + +type alias Position = + Float + + +type alias Velocity = + Float + + +type alias Particle = + { pos : List Position, vel : List Velocity } + + +type Status + = Idle + | Running + + +type alias Drag = + { start : Float + , current : Float + } + + +getX : Particle -> Position +getX p = + Maybe.withDefault 0 <| List.head <| .pos p + + +getV : Particle -> Velocity +getV p = + Maybe.withDefault 0 <| List.head <| .vel p + + +getX0 : Model -> Position +getX0 m = + let + scale x = + 3 - 6 * x / m.wHeight + in + case m.drag of + Nothing -> + getX m.part + + Just { start, current } -> + getX m.part + scale current - scale start + + +resetParticle : Particle -> Particle +resetParticle { pos, vel } = + case ( List.reverse pos, List.reverse vel ) of + ( x :: _, v :: _ ) -> + Particle [ x ] [ v ] + + _ -> + Particle [ x0 ] [ 0 ] + + + +-- UPDATE + + +type Msg + = Start + | Stop + | Tick Posix + | GetViewPort Viewport + | SliderUpdate Float + | SliderMsg Slider.Msg + | DragStart Float + | DragAt Float + | DragEnd Float + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update msg model = + case msg of + Start -> + ( { model + | status = Running + , t = 0 + , dt = model.dt0 + , drag = Nothing + , part = resetParticle model.part + } + , Cmd.none + ) + + Stop -> + ( { model + | status = Idle + , part = resetParticle model.part + , t = 0 + } + , Cmd.none + ) + + Tick _ -> + case model.status of + Idle -> + ( model, Cmd.none ) + + Running -> + if model.t > 5 + model.dt then + ( { model + | status = Idle + , part = Particle [ x0 ] [ 0 ] + , history = ( model.dt, model.t, model.part ) :: model.history + , t = 0 + } + , Cmd.none + ) + + else + ( { model + | part = evolve model.part model.t model.dt + , t = model.t + model.dt + } + , Task.perform GetViewPort Browser.Dom.getViewport + ) + + GetViewPort { viewport } -> + ( { model | wWidth = viewport.width, wHeight = viewport.height * 8 / 10 }, Cmd.none ) + + SliderUpdate dt -> + ( { model | dt0 = dt }, Cmd.none ) + + SliderMsg sliderMsg -> + let + ( newSlider, cmd, updateResults ) = + Slider.update sliderMsg model.slider + + newModel = + { model | slider = newSlider, dt0 = newSlider.value } + + newCmd = + if updateResults then + Cmd.batch [ Cmd.map SliderMsg cmd, Cmd.none ] + + else + Cmd.none + in + ( newModel, newCmd ) + + DragStart y -> + case model.status of + Idle -> + ( { model | drag = Just (Drag y y) }, Cmd.none ) + + Running -> + ( model, Cmd.none ) + + DragAt y -> + ( { model | drag = Maybe.map (\{ start } -> Drag start y) model.drag } + , Cmd.none + ) + + DragEnd _ -> + ( { model + | drag = Nothing + , part = Particle [ getX0 model ] [ k * getX0 model ] + } + , Cmd.none + ) + + +k : Float +k = + -2 + + +diffEq : Position -> Velocity -> Time -> Time -> ( Position, Velocity ) +diffEq x _ _ dt = + ( x + (k * x) * dt, k * (x + (k * x) * dt) ) + + +evolve : Particle -> Time -> Time -> Particle +evolve p t dt = + let + ( x, v ) = + diffEq (getX p) (getV p) t dt + in + { p | pos = x :: p.pos, vel = v :: p.vel } + + + +-- SUBSCRIPTIONS + + +subscriptions : Model -> Sub Msg +subscriptions model = + (Slider.subscriptions model.slider |> Sub.map SliderMsg) + :: (case model.drag of + Nothing -> + [ Time.every (model.dt * 1000) Tick ] + + Just _ -> + [ Events.onMouseMove (Decode.map DragAt decodeMouseHeight) + , Events.onMouseUp (Decode.map DragEnd decodeMouseHeight) + ] + ) + |> Sub.batch + + +decodeMouseHeight : Decoder Float +decodeMouseHeight = + Decode.field "pageY" Decode.float + + + +-- VIEW + + +view : Model -> Html Msg +view model = + div [] + [ h3 [] [ text "Drag the ball up or down, pick a dt and click Start" ] + , h3 [ style "color" (gradient model.dt0) ] + [ viewSlider model.slider + , button [ onClick Start ] [ text "Start" ] + , button [ onClick Stop ] [ text "Stop" ] + , text ("dt = " ++ String.fromFloat model.dt0) + ] + , svg + [ width (String.fromFloat model.wWidth) + , height (String.fromFloat model.wHeight) + , stroke "black" + ] + ([ line + [ x1 "0" + , x2 (String.fromFloat model.wWidth) + , y1 (String.fromFloat (model.wHeight / 2)) + , y2 (String.fromFloat (model.wHeight / 2)) + ] + [] + , line + [ x1 (String.fromFloat (model.wWidth / 20)) + , x2 (String.fromFloat (model.wWidth / 20)) + , y1 "0" + , y2 (String.fromFloat model.wHeight) + ] + [] + , viewCircle model + ] + ++ plotHistory model + ) + ] + + +viewSlider : Slider.Model -> Html Msg +viewSlider slider = + Slider.view slider |> Html.map SliderMsg + + +scaleX : Float -> Position -> String +scaleX h x = + String.fromFloat (h / 2 * (1 - x / 3)) + + +scaleT : Float -> Time -> String +scaleT w t = + String.fromFloat (w * (0.05 + t / 5)) + + +viewCircle : Model -> Html Msg +viewCircle m = + circle + [ cy (scaleX m.wHeight (getX0 m)) + , cx (scaleT m.wWidth m.t) + , r "10" + , on "mousedown" (Decode.map DragStart decodeMouseHeight) + ] + [] + + +plotPath : Float -> Float -> ( Time, Time, Particle ) -> String +plotPath w h ( dt, tf, particle ) = + let + comb x ( t, s ) = + ( t - dt, s ++ scaleT w t ++ "," ++ scaleX h x ++ " " ) + in + Tuple.second <| List.foldl comb ( tf, "" ) particle.pos + + +plotHistory : Model -> List (Html Msg) +plotHistory m = + let + ( w, h ) = + ( m.wWidth, m.wHeight ) + in + List.map + (\( dt, t, p ) -> + polyline + [ stroke "black" + , fill "none" + , stroke (gradient dt) + , points (plotPath w h ( dt, t, p )) + ] + [] + ) + (( m.dt, m.t, m.part ) :: m.history) + + +gradient : Time -> String +gradient dt = + let + ( r, g, b ) = + ( round (255 * dt), 0, round (255 * (1 - dt)) ) + + col = + Hex.toString (256 * (256 * r + g) + b) + in + if String.length col < 6 then + "#" ++ String.repeat (6 - String.length col) "0" ++ col + + else + "#" ++ col diff --git a/contents/forward_euler_method/forward_euler_method.md b/contents/forward_euler_method/forward_euler_method.md index 175ef1337..d4aa7375c 100644 --- a/contents/forward_euler_method/forward_euler_method.md +++ b/contents/forward_euler_method/forward_euler_method.md @@ -116,11 +116,11 @@ Note that in this case, the velocity is directly given by the ODE and the accele {% sample lang="rs" %} [import, lang:"rust"](code/rust/euler.rs) {% sample lang="elm" %} -[import:44-54, lang:"elm"](code/elm/euler.elm) -[import:193-210, lang:"elm"](code/elm/euler.elm) +[import:78-91, lang:"elm"](code/elm/src/Euler.elm) +[import:236-252, lang:"elm"](code/elm/src/Euler.elm) Full code for the visualization follows: -[import, lang:"elm"](code/elm/euler.elm) +[import, lang:"elm"](code/elm/src/Euler.elm) {% sample lang="py" %} [import, lang:"python"](code/python/euler.py) From 7fe5bfe9e5a7972916d4edc874165d498bcaacba Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Sun, 7 Nov 2021 16:25:18 +0100 Subject: [PATCH 067/146] Standardise code directory names (#920) * Rename c++ directories to cpp * Rename golang folders to go * Change paths to code in chapter files Co-authored-by: James Schloss --- contents/IFS/IFS.md | 4 +-- contents/IFS/code/{c++ => cpp}/IFS.cpp | 0 .../approximate_counting.md | 2 +- .../{c++ => cpp}/approximate_counting.cpp | 0 contents/barnsley/barnsley.md | 2 +- .../barnsley/code/{c++ => cpp}/barnsley.cpp | 0 .../code/{c++ => cpp}/gauss_easter.cpp | 0 contents/computus/computus.md | 2 +- .../cooley_tukey/code/{c++ => cpp}/fft.cpp | 0 contents/cooley_tukey/cooley_tukey.md | 6 ++-- .../code/{c++ => cpp}/euclidean.cpp | 0 .../euclidean_algorithm.md | 6 ++-- .../code/{c++ => cpp}/euler.cpp | 0 .../code/{golang => go}/euler.go | 0 .../forward_euler_method.md | 4 +-- .../{c++ => cpp}/gaussian_elimination.cpp | 0 .../gaussian_elimination.md | 12 ++++---- .../code/{c++ => cpp}/graham_scan.cpp | 0 .../graham_scan/code/{golang => go}/graham.go | 0 contents/graham_scan/graham_scan.md | 12 ++++---- .../code/{c++ => cpp}/huffman.cpp | 0 .../code/{golang => go}/huffman.go | 0 contents/huffman_encoding/huffman_encoding.md | 4 +-- .../code/{c++ => cpp}/jarvis_march.cpp | 0 .../code/{golang => go}/jarvis.go | 0 contents/jarvis_march/jarvis_march.md | 4 +-- .../code/{c++ => cpp}/monte_carlo.cpp | 0 .../monte_carlo_integration.md | 4 +-- contents/quantum_systems/quantum_systems.md | 2 +- .../code/{c++ => cpp}/split_op.cpp | 0 .../split-operator_method.md | 8 +++--- .../code/{c++ => cpp}/stable_marriage.cpp | 0 .../stable_marriage_problem.md | 2 +- .../code/{c++ => cpp}/thomas.cpp | 0 .../code/{golang => go}/thomas.go | 0 contents/thomas_algorithm/thomas_algorithm.md | 4 +-- .../code/{c++ => cpp}/tree_example.cpp | 0 .../code/{golang => go}/treetraversal.go | 0 contents/tree_traversal/tree_traversal.md | 28 +++++++++---------- .../code/{c++ => cpp}/verlet.cpp | 0 .../code/{golang => go}/verlet.go | 0 .../verlet_integration/verlet_integration.md | 16 +++++------ 42 files changed, 61 insertions(+), 61 deletions(-) rename contents/IFS/code/{c++ => cpp}/IFS.cpp (100%) rename contents/approximate_counting/code/{c++ => cpp}/approximate_counting.cpp (100%) rename contents/barnsley/code/{c++ => cpp}/barnsley.cpp (100%) rename contents/computus/code/{c++ => cpp}/gauss_easter.cpp (100%) rename contents/cooley_tukey/code/{c++ => cpp}/fft.cpp (100%) rename contents/euclidean_algorithm/code/{c++ => cpp}/euclidean.cpp (100%) rename contents/forward_euler_method/code/{c++ => cpp}/euler.cpp (100%) rename contents/forward_euler_method/code/{golang => go}/euler.go (100%) rename contents/gaussian_elimination/code/{c++ => cpp}/gaussian_elimination.cpp (100%) rename contents/graham_scan/code/{c++ => cpp}/graham_scan.cpp (100%) rename contents/graham_scan/code/{golang => go}/graham.go (100%) rename contents/huffman_encoding/code/{c++ => cpp}/huffman.cpp (100%) rename contents/huffman_encoding/code/{golang => go}/huffman.go (100%) rename contents/jarvis_march/code/{c++ => cpp}/jarvis_march.cpp (100%) rename contents/jarvis_march/code/{golang => go}/jarvis.go (100%) rename contents/monte_carlo_integration/code/{c++ => cpp}/monte_carlo.cpp (100%) rename contents/split-operator_method/code/{c++ => cpp}/split_op.cpp (100%) rename contents/stable_marriage_problem/code/{c++ => cpp}/stable_marriage.cpp (100%) rename contents/thomas_algorithm/code/{c++ => cpp}/thomas.cpp (100%) rename contents/thomas_algorithm/code/{golang => go}/thomas.go (100%) rename contents/tree_traversal/code/{c++ => cpp}/tree_example.cpp (100%) rename contents/tree_traversal/code/{golang => go}/treetraversal.go (100%) rename contents/verlet_integration/code/{c++ => cpp}/verlet.cpp (100%) rename contents/verlet_integration/code/{golang => go}/verlet.go (100%) diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index 2ed1fe484..9431e4631 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -135,7 +135,7 @@ Here, instead of tracking children of children, we track a single individual tha {% sample lang="hs" %} [import:7-13, lang:"haskell"](code/haskell/IFS.hs) {% sample lang="cpp" %} -[import:39-52, lang:"cpp"](code/c++/IFS.cpp) +[import:39-52, lang:"cpp"](code/cpp/IFS.cpp) {% sample lang="py" %} [import:5-12, lang:"python"](code/python/IFS.py) {% sample lang="c" %} @@ -221,7 +221,7 @@ In addition, we have written the chaos game code to take in a set of points so t {% sample lang="hs" %} [import, lang:"haskell"](code/haskell/IFS.hs) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/IFS.cpp) +[import, lang:"cpp"](code/cpp/IFS.cpp) {% sample lang="py" %} [import, lang:"python"](code/python/IFS.py) {% sample lang="c" %} diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/cpp/IFS.cpp similarity index 100% rename from contents/IFS/code/c++/IFS.cpp rename to contents/IFS/code/cpp/IFS.cpp diff --git a/contents/approximate_counting/approximate_counting.md b/contents/approximate_counting/approximate_counting.md index 654721844..ae4a765d6 100644 --- a/contents/approximate_counting/approximate_counting.md +++ b/contents/approximate_counting/approximate_counting.md @@ -363,7 +363,7 @@ As we do not have any objects to count, we will instead simulate the counting wi {% sample lang="c" %} [import, lang:"c"](code/c/approximate_counting.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/approximate_counting.cpp) +[import, lang:"cpp"](code/cpp/approximate_counting.cpp) {% sample lang="python" %} [import, lang:"python"](code/python/approximate_counting.py) {% endmethod %} diff --git a/contents/approximate_counting/code/c++/approximate_counting.cpp b/contents/approximate_counting/code/cpp/approximate_counting.cpp similarity index 100% rename from contents/approximate_counting/code/c++/approximate_counting.cpp rename to contents/approximate_counting/code/cpp/approximate_counting.cpp diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index f696b9ffb..c879d7bbd 100644 --- a/contents/barnsley/barnsley.md +++ b/contents/barnsley/barnsley.md @@ -128,7 +128,7 @@ The biggest differences between the two code implementations is that the Barnsle {% sample lang="rs" %} [import, lang:"rust"](code/rust/src/main.rs) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/barnsley.cpp) +[import, lang:"cpp"](code/cpp/barnsley.cpp) {% sample lang="c" %} [import, lang:"c"](code/c/barnsley.c) {% sample lang="java" %} diff --git a/contents/barnsley/code/c++/barnsley.cpp b/contents/barnsley/code/cpp/barnsley.cpp similarity index 100% rename from contents/barnsley/code/c++/barnsley.cpp rename to contents/barnsley/code/cpp/barnsley.cpp diff --git a/contents/computus/code/c++/gauss_easter.cpp b/contents/computus/code/cpp/gauss_easter.cpp similarity index 100% rename from contents/computus/code/c++/gauss_easter.cpp rename to contents/computus/code/cpp/gauss_easter.cpp diff --git a/contents/computus/computus.md b/contents/computus/computus.md index 0b474c9a9..3a881cdb0 100644 --- a/contents/computus/computus.md +++ b/contents/computus/computus.md @@ -315,7 +315,7 @@ For now, we have the code outputting a tuple of $$d$$ and $$e$$, so users can us {% sample lang="c" %} [import, lang:"c"](code/c/gauss_easter.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/gauss_easter.cpp) +[import, lang:"cpp"](code/cpp/gauss_easter.cpp) {% sample lang="lisp" %} [import, lang:"lisp"](code/clisp/gauss-easter.lisp) {% sample lang="nim" %} diff --git a/contents/cooley_tukey/code/c++/fft.cpp b/contents/cooley_tukey/code/cpp/fft.cpp similarity index 100% rename from contents/cooley_tukey/code/c++/fft.cpp rename to contents/cooley_tukey/code/cpp/fft.cpp diff --git a/contents/cooley_tukey/cooley_tukey.md b/contents/cooley_tukey/cooley_tukey.md index 67309b5d2..b30052e40 100644 --- a/contents/cooley_tukey/cooley_tukey.md +++ b/contents/cooley_tukey/cooley_tukey.md @@ -76,7 +76,7 @@ For some reason, though, putting code to this transformation really helped me fi {% sample lang="clj" %} [import:15-30, lang:"clojure"](code/clojure/fft.clj) {% sample lang="cpp" %} -[import:23-33, lang:"cpp"](code/c++/fft.cpp) +[import:23-33, lang:"cpp"](code/cpp/fft.cpp) {% sample lang="hs" %} [import:7-13, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} @@ -129,7 +129,7 @@ In the end, the code looks like: {% sample lang="clj" %} [import:31-58, lang:"clojure"](code/clojure/fft.clj) {% sample lang="cpp" %} -[import:36-66, lang:"cpp"](code/c++/fft.cpp) +[import:36-66, lang:"cpp"](code/cpp/fft.cpp) {% sample lang="hs" %} [import:15-28, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} @@ -242,7 +242,7 @@ Note: I implemented this in Julia because the code seems more straightforward in {% sample lang="clj" %} [import, lang:"clojure"](code/clojure/fft.clj) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/fft.cpp) +[import, lang:"cpp"](code/cpp/fft.cpp) {% sample lang="hs" %} [import, lang:"haskell"](code/haskell/fft.hs) {% sample lang="py" %} diff --git a/contents/euclidean_algorithm/code/c++/euclidean.cpp b/contents/euclidean_algorithm/code/cpp/euclidean.cpp similarity index 100% rename from contents/euclidean_algorithm/code/c++/euclidean.cpp rename to contents/euclidean_algorithm/code/cpp/euclidean.cpp diff --git a/contents/euclidean_algorithm/euclidean_algorithm.md b/contents/euclidean_algorithm/euclidean_algorithm.md index f44c3acb7..1d6211a37 100644 --- a/contents/euclidean_algorithm/euclidean_algorithm.md +++ b/contents/euclidean_algorithm/euclidean_algorithm.md @@ -14,7 +14,7 @@ The algorithm is a simple way to find the *greatest common divisor* (GCD) of two {% sample lang="clj" %} [import:2-8, lang="clojure"](code/clojure/euclidean_example.clj) {% sample lang="cpp" %} -[import:18-31, lang="c_cpp"](code/c++/euclidean.cpp) +[import:18-31, lang="c_cpp"](code/cpp/euclidean.cpp) {% sample lang="java" %} [import:3-16, lang="java"](code/java/EuclideanAlgo.java) {% sample lang="kotlin" %} @@ -104,7 +104,7 @@ Modern implementations, though, often use the modulus operator (%) like so {% sample lang="clj" %} [import:9-13, lang="clojure"](code/clojure/euclidean_example.clj) {% sample lang="cpp" %} -[import:5-15, lang="c_cpp"](code/c++/euclidean.cpp) +[import:5-15, lang="c_cpp"](code/cpp/euclidean.cpp) {% sample lang="java" %} [import:18-26, lang="java"](code/java/EuclideanAlgo.java) {% sample lang="kotlin" %} @@ -207,7 +207,7 @@ Here's a video on the Euclidean algorithm: {% sample lang="clj" %} [import, lang="clojure"](code/clojure/euclidean_example.clj) {% sample lang="cpp" %} -[import, lang="c_cpp"](code/c++/euclidean.cpp) +[import, lang="c_cpp"](code/cpp/euclidean.cpp) {% sample lang="java" %} [import, lang="java"](code/java/EuclideanAlgo.java) {% sample lang="kotlin" %} diff --git a/contents/forward_euler_method/code/c++/euler.cpp b/contents/forward_euler_method/code/cpp/euler.cpp similarity index 100% rename from contents/forward_euler_method/code/c++/euler.cpp rename to contents/forward_euler_method/code/cpp/euler.cpp diff --git a/contents/forward_euler_method/code/golang/euler.go b/contents/forward_euler_method/code/go/euler.go similarity index 100% rename from contents/forward_euler_method/code/golang/euler.go rename to contents/forward_euler_method/code/go/euler.go diff --git a/contents/forward_euler_method/forward_euler_method.md b/contents/forward_euler_method/forward_euler_method.md index d4aa7375c..f97ff27a2 100644 --- a/contents/forward_euler_method/forward_euler_method.md +++ b/contents/forward_euler_method/forward_euler_method.md @@ -112,7 +112,7 @@ Note that in this case, the velocity is directly given by the ODE and the accele {% sample lang="c" %} [import, lang:"c"](code/c/euler.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/euler.cpp) +[import, lang:"cpp"](code/cpp/euler.cpp) {% sample lang="rs" %} [import, lang:"rust"](code/rust/euler.rs) {% sample lang="elm" %} @@ -135,7 +135,7 @@ Full code for the visualization follows: {% sample lang="f90" %} [import, lang:"fortran"](code/fortran/euler.f90) {% sample lang="go" %} -[import, lang:"go"](code/golang/euler.go) +[import, lang:"go"](code/go/euler.go) {% sample lang="v" %} [import, lang:"v"](code/v/euler.v) {% sample lang="asm-x64" %} diff --git a/contents/gaussian_elimination/code/c++/gaussian_elimination.cpp b/contents/gaussian_elimination/code/cpp/gaussian_elimination.cpp similarity index 100% rename from contents/gaussian_elimination/code/c++/gaussian_elimination.cpp rename to contents/gaussian_elimination/code/cpp/gaussian_elimination.cpp diff --git a/contents/gaussian_elimination/gaussian_elimination.md b/contents/gaussian_elimination/gaussian_elimination.md index 7f8e005af..8caf869ed 100644 --- a/contents/gaussian_elimination/gaussian_elimination.md +++ b/contents/gaussian_elimination/gaussian_elimination.md @@ -315,7 +315,7 @@ In code, this process might look like this: [import:5-13, lang:"c"](code/c/gaussian_elimination.c) [import:19-34, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import:13-23, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import:13-23, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="hs" %} [import:10-17, lang:"haskell"](code/haskell/gaussianElimination.hs) [import:44-46, lang:"haskell"](code/haskell/gaussianElimination.hs) @@ -389,7 +389,7 @@ Here is what it might look like in code: {% sample lang="c" %} [import:36-41, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import:25-32, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import:25-32, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="hs" %} [import:19-33, lang:"haskell"](code/haskell/gaussianElimination.hs) [import:42-42, lang:"haskell"](code/haskell/gaussianElimination.hs) @@ -412,7 +412,7 @@ When we put everything together, it looks like this: {% sample lang="c" %} [import:15-48, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import:8-34, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import:8-34, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="hs" %} [import:10-36, lang:"haskell"](code/haskell/gaussianElimination.hs) {% sample lang="py" %} @@ -453,7 +453,7 @@ Here it is in code: {% sample lang="c" %} [import:64-82, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import:36-54, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import:36-54, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="hs" %} [import:38-46, lang:"haskell"](code/haskell/gaussianElimination.hs) {% sample lang="py" %} @@ -497,7 +497,7 @@ In code, it looks like this: {% sample lang="c" %} [import:50-62, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import:56-72, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import:56-72, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="rs" %} [import:98-112, lang:"rust"](code/rust/gaussian_elimination.rs) {% sample lang="hs" %} @@ -567,7 +567,7 @@ Here's a video describing Gaussian elimination: {% sample lang="c" %} [import, lang:"c"](code/c/gaussian_elimination.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/gaussian_elimination.cpp) +[import, lang:"cpp"](code/cpp/gaussian_elimination.cpp) {% sample lang="rs" %} [import, lang:"rust"](code/rust/gaussian_elimination.rs) {% sample lang="hs" %} diff --git a/contents/graham_scan/code/c++/graham_scan.cpp b/contents/graham_scan/code/cpp/graham_scan.cpp similarity index 100% rename from contents/graham_scan/code/c++/graham_scan.cpp rename to contents/graham_scan/code/cpp/graham_scan.cpp diff --git a/contents/graham_scan/code/golang/graham.go b/contents/graham_scan/code/go/graham.go similarity index 100% rename from contents/graham_scan/code/golang/graham.go rename to contents/graham_scan/code/go/graham.go diff --git a/contents/graham_scan/graham_scan.md b/contents/graham_scan/graham_scan.md index 586d209db..7b84f3acd 100644 --- a/contents/graham_scan/graham_scan.md +++ b/contents/graham_scan/graham_scan.md @@ -23,13 +23,13 @@ We can find whether a rotation is counter-clockwise with trigonometric functions {% sample lang="py" %} [import:4-6, lang:"python"](code/python/graham_scan.py) {% sample lang="go" %} -[import:13-15, lang:"go"](code/golang/graham.go) +[import:13-15, lang:"go"](code/go/graham.go) {% sample lang="java" %} [import:27-29, lang:"java"](code/java/GrahamScan.java) {% sample lang="lisp" %} [import:5-13, lang:"lisp"](code/clisp/graham-scan.lisp) {% sample lang="cpp" %} -[import:18-20, lang="cpp"](code/c++/graham_scan.cpp) +[import:18-20, lang="cpp"](code/cpp/graham_scan.cpp) {% sample lang="coco" %} [import:4-8, lang="coconut"](code/coconut/graham_scan.coco) {% endmethod %} @@ -57,13 +57,13 @@ In the end, the code should look something like this: {% sample lang="py" %} [import:14-28, lang:"python"](code/python/graham_scan.py) {% sample lang="go" %} -[import:21-42, lang:"go"](code/golang/graham.go) +[import:21-42, lang:"go"](code/go/graham.go) {% sample lang="java" %} [import:35-70, lang:"java"](code/java/GrahamScan.java) {% sample lang="lisp" %} [import:15-58, lang:"lisp"](code/clisp/graham-scan.lisp) {% sample lang="cpp" %} -[import:26-62, lang="cpp"](code/c++/graham_scan.cpp) +[import:26-62, lang="cpp"](code/cpp/graham_scan.cpp) {% sample lang="coco" %} [import:17-30, lang="coconut"](code/coconut/graham_scan.coco) {% endmethod %} @@ -86,13 +86,13 @@ In the end, the code should look something like this: {% sample lang="py" %} [import, lang:"python"](code/python/graham_scan.py) {% sample lang="go" %} -[import, lang:"go"](code/golang/graham.go) +[import, lang:"go"](code/go/graham.go) {% sample lang="java" %} [import, lang:"java"](code/java/GrahamScan.java) {% sample lang="lisp" %} [import, lang:"lisp"](code/clisp/graham-scan.lisp) {% sample lang="cpp" %} -[import, lang="cpp"](code/c++/graham_scan.cpp) +[import, lang="cpp"](code/cpp/graham_scan.cpp) {%sample lang="coco" %} [import, lang="coconut"](code/coconut/graham_scan.coco) {% endmethod %} diff --git a/contents/huffman_encoding/code/c++/huffman.cpp b/contents/huffman_encoding/code/cpp/huffman.cpp similarity index 100% rename from contents/huffman_encoding/code/c++/huffman.cpp rename to contents/huffman_encoding/code/cpp/huffman.cpp diff --git a/contents/huffman_encoding/code/golang/huffman.go b/contents/huffman_encoding/code/go/huffman.go similarity index 100% rename from contents/huffman_encoding/code/golang/huffman.go rename to contents/huffman_encoding/code/go/huffman.go diff --git a/contents/huffman_encoding/huffman_encoding.md b/contents/huffman_encoding/huffman_encoding.md index 44bc1e783..3772c97ca 100644 --- a/contents/huffman_encoding/huffman_encoding.md +++ b/contents/huffman_encoding/huffman_encoding.md @@ -78,7 +78,7 @@ Whether you use a stack or straight-up recursion also depends on the language, b {% sample lang="lua" %} [import, lang="lua"](code/lua/huffman.lua) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/huffman.cpp) +[import, lang:"cpp"](code/cpp/huffman.cpp) {% sample lang="clj" %} [import, lang:"clojure"](code/clojure/huffman.clj) {% sample lang="py" %} @@ -88,7 +88,7 @@ Whether you use a stack or straight-up recursion also depends on the language, b {% sample lang="java" %} [import, lang:"java"](code/java/huffman.java) {% sample lang="go" %} -[import, lang:"go"](code/golang/huffman.go) +[import, lang:"go"](code/go/huffman.go) {% sample lang="asm-x64" %} [import, lang:"asm-x64"](code/asm-x64/huffman.s) {% sample lang="scala" %} diff --git a/contents/jarvis_march/code/c++/jarvis_march.cpp b/contents/jarvis_march/code/cpp/jarvis_march.cpp similarity index 100% rename from contents/jarvis_march/code/c++/jarvis_march.cpp rename to contents/jarvis_march/code/cpp/jarvis_march.cpp diff --git a/contents/jarvis_march/code/golang/jarvis.go b/contents/jarvis_march/code/go/jarvis.go similarity index 100% rename from contents/jarvis_march/code/golang/jarvis.go rename to contents/jarvis_march/code/go/jarvis.go diff --git a/contents/jarvis_march/jarvis_march.md b/contents/jarvis_march/jarvis_march.md index fa244713e..20929d4ad 100644 --- a/contents/jarvis_march/jarvis_march.md +++ b/contents/jarvis_march/jarvis_march.md @@ -39,13 +39,13 @@ Since this algorithm, there have been many other algorithms that have advanced t {% sample lang="py" %} [import, lang:"python"](code/python/jarvis_march.py) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/jarvis_march.cpp) +[import, lang:"cpp"](code/cpp/jarvis_march.cpp) {% sample lang="lisp" %} [import, lang:"lisp"](code/clisp/jarvis-march.lisp) {% sample lang="java" %} [import, lang:"java"](code/java/JarvisMarch.java) {% sample lang="go" %} -[import, lang:"go"](code/golang/jarvis.go) +[import, lang:"go"](code/go/jarvis.go) {% sample lang="v" %} [import, lang:"v"](code/v/jarvis.v) {% sample lang="rust" %} diff --git a/contents/monte_carlo_integration/code/c++/monte_carlo.cpp b/contents/monte_carlo_integration/code/cpp/monte_carlo.cpp similarity index 100% rename from contents/monte_carlo_integration/code/c++/monte_carlo.cpp rename to contents/monte_carlo_integration/code/cpp/monte_carlo.cpp diff --git a/contents/monte_carlo_integration/monte_carlo_integration.md b/contents/monte_carlo_integration/monte_carlo_integration.md index cf5640ffa..964de7bbe 100644 --- a/contents/monte_carlo_integration/monte_carlo_integration.md +++ b/contents/monte_carlo_integration/monte_carlo_integration.md @@ -44,7 +44,7 @@ each point is tested to see whether it's in the circle or not: {% sample lang="c" %} [import:7-9, lang:"c"](code/c/monte_carlo.c) {% sample lang="cpp" %} -[import:7-16, lang:"cpp"](code/c++/monte_carlo.cpp) +[import:7-16, lang:"cpp"](code/cpp/monte_carlo.cpp) {% sample lang="js" %} [import:2-6, lang:"javascript"](code/javascript/monte_carlo.js) {% sample lang="hs" %} @@ -147,7 +147,7 @@ Feel free to submit your version via pull request, and thanks for reading! {% sample lang="c" %} [import, lang:"c"](code/c/monte_carlo.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/monte_carlo.cpp) +[import, lang:"cpp"](code/cpp/monte_carlo.cpp) {% sample lang="js" %} [import, lang:"javascript"](code/javascript/monte_carlo.js) {% sample lang="hs" %} diff --git a/contents/quantum_systems/quantum_systems.md b/contents/quantum_systems/quantum_systems.md index a7a762ca5..c602aaea1 100644 --- a/contents/quantum_systems/quantum_systems.md +++ b/contents/quantum_systems/quantum_systems.md @@ -232,7 +232,7 @@ This ultimately looks like this: {% sample lang="c" %} [import:150-184, lang:"c"](../split-operator_method/code/c/split_op.c) {% sample lang="cpp" %} -[import:158-189, lang:"cpp"](../split-operator_method/code/c++/split_op.cpp) +[import:158-189, lang:"cpp"](../split-operator_method/code/cpp/split_op.cpp) {% sample lang="py" %} [import:98-112, lang:"python"](../split-operator_method/code/python/split_op.py) {% endmethod %} diff --git a/contents/split-operator_method/code/c++/split_op.cpp b/contents/split-operator_method/code/cpp/split_op.cpp similarity index 100% rename from contents/split-operator_method/code/c++/split_op.cpp rename to contents/split-operator_method/code/cpp/split_op.cpp diff --git a/contents/split-operator_method/split-operator_method.md b/contents/split-operator_method/split-operator_method.md index 33af1f225..ad4fd6c0e 100644 --- a/contents/split-operator_method/split-operator_method.md +++ b/contents/split-operator_method/split-operator_method.md @@ -103,7 +103,7 @@ Regardless, we first need to set all the initial parameters, including the initi [import:11-21, lang:"c"](code/c/split_op.c) [import:52-73, lang:"c"](code/c/split_op.c) {% sample lang="cpp" %} -[import:14-49, lang:"cpp"](code/c++/split_op.cpp) +[import:14-49, lang:"cpp"](code/cpp/split_op.cpp) {% sample lang="py" %} [import:11-30, lang:"python"](code/python/split_op.py) {% sample lang="hs" %} @@ -126,7 +126,7 @@ Afterwards, we turn them into operators: [import:23-29, lang:"c"](code/c/split_op.c) [import:75-96, lang:"c"](code/c/split_op.c) {% sample lang="cpp" %} -[import:51-80, lang:"cpp"](code/c++/split_op.cpp) +[import:51-80, lang:"cpp"](code/cpp/split_op.cpp) {% sample lang="py" %} [import:33-54, lang:"python"](code/python/split_op.py) {% sample lang="hs" %} @@ -149,7 +149,7 @@ The final step is to do the iteration, itself. {% sample lang="c" %} [import:98-148, lang:"c"](code/c/split_op.c) {% sample lang="cpp" %} -[import:99-156, lang:"cpp"](code/c++/split_op.cpp) +[import:99-156, lang:"cpp"](code/cpp/split_op.cpp) {% sample lang="py" %} [import:57-95, lang:"python"](code/python/split_op.py) {% sample lang="hs" %} @@ -186,7 +186,7 @@ Checking to make sure your code can output the correct energy for a harmonic tra {% sample lang="c" %} [import, lang:"c"](code/c/split_op.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/split_op.cpp) +[import, lang:"cpp"](code/cpp/split_op.cpp) {% sample lang="py" %} [import:5-127, lang:"python"](code/python/split_op.py) {% sample lang="hs" %} diff --git a/contents/stable_marriage_problem/code/c++/stable_marriage.cpp b/contents/stable_marriage_problem/code/cpp/stable_marriage.cpp similarity index 100% rename from contents/stable_marriage_problem/code/c++/stable_marriage.cpp rename to contents/stable_marriage_problem/code/cpp/stable_marriage.cpp diff --git a/contents/stable_marriage_problem/stable_marriage_problem.md b/contents/stable_marriage_problem/stable_marriage_problem.md index 3121c6478..2e8850a01 100644 --- a/contents/stable_marriage_problem/stable_marriage_problem.md +++ b/contents/stable_marriage_problem/stable_marriage_problem.md @@ -40,7 +40,7 @@ Here is a video describing the stable marriage problem: {% sample lang="c" %} [import, lang:"c"](code/c/stable_marriage.c) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/stable_marriage.cpp) +[import, lang:"cpp"](code/cpp/stable_marriage.cpp) {% sample lang="js" %} [import, lang:"javascript"](code/javascript/stable-marriage.js) {% sample lang="cs" %} diff --git a/contents/thomas_algorithm/code/c++/thomas.cpp b/contents/thomas_algorithm/code/cpp/thomas.cpp similarity index 100% rename from contents/thomas_algorithm/code/c++/thomas.cpp rename to contents/thomas_algorithm/code/cpp/thomas.cpp diff --git a/contents/thomas_algorithm/code/golang/thomas.go b/contents/thomas_algorithm/code/go/thomas.go similarity index 100% rename from contents/thomas_algorithm/code/golang/thomas.go rename to contents/thomas_algorithm/code/go/thomas.go diff --git a/contents/thomas_algorithm/thomas_algorithm.md b/contents/thomas_algorithm/thomas_algorithm.md index 5af6c3334..81bb47617 100644 --- a/contents/thomas_algorithm/thomas_algorithm.md +++ b/contents/thomas_algorithm/thomas_algorithm.md @@ -112,7 +112,7 @@ You will find this algorithm implemented [in this project](https://scratch.mit.e {% sample lang="hs" %} [import, lang:"haskell"](code/haskell/thomas.hs) {% sample lang="go" %} -[import, lang:"go"](code/golang/thomas.go) +[import, lang:"go"](code/go/thomas.go) {% sample lang="v" %} [import, lang:"v"](code/v/thomas.v) {% sample lang="swift" %} @@ -122,7 +122,7 @@ You will find this algorithm implemented [in this project](https://scratch.mit.e {% sample lang="nim" %} [import, lang:"nim"](code/nim/thomas_algorithm.nim) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/thomas.cpp) +[import, lang:"cpp"](code/cpp/thomas.cpp) {% sample lang="lua" %} [import, lang:"lua"](code/lua/thomas.lua) {% sample lang="crystal" %} diff --git a/contents/tree_traversal/code/c++/tree_example.cpp b/contents/tree_traversal/code/cpp/tree_example.cpp similarity index 100% rename from contents/tree_traversal/code/c++/tree_example.cpp rename to contents/tree_traversal/code/cpp/tree_example.cpp diff --git a/contents/tree_traversal/code/golang/treetraversal.go b/contents/tree_traversal/code/go/treetraversal.go similarity index 100% rename from contents/tree_traversal/code/golang/treetraversal.go rename to contents/tree_traversal/code/go/treetraversal.go diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index 4b6c5b762..5dc6657e0 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -6,7 +6,7 @@ Trees are naturally recursive data structures, and because of this, we cannot ac {% sample lang="jl" %} [import:3-7, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:12-15, lang:"cpp"](code/c++/tree_example.cpp) +[import:12-15, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:6-10, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -35,7 +35,7 @@ As a note, a `node` struct is not necessary in javascript, so this is an example {% sample lang="st" %} [import:1-20, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:5-8, lang:"go"](code/golang/treetraversal.go) +[import:5-8, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:24-27, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -54,7 +54,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="jl" %} [import:9-16, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:17-24, lang:"cpp"](code/c++/tree_example.cpp) +[import:17-24, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:33-44, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -82,7 +82,7 @@ Because of this, the most straightforward way to traverse the tree might be recu {% sample lang="st" %} [import:22-27, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:10-15, lang:"go"](code/golang/treetraversal.go) +[import:10-15, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:290-314, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -110,7 +110,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="jl" %} [import:18-26, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:26-31, lang:"cpp"](code/c++/tree_example.cpp) +[import:26-31, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:46-57, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -138,7 +138,7 @@ Now, in this case the first element searched through is still the root of the tr {% sample lang="st" %} [import:29-34, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:17-22, lang:"go"](code/golang/treetraversal.go) +[import:17-22, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:316-344, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -161,7 +161,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="jl" %} [import:28-43, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:34-52 lang:"cpp"](code/c++/tree_example.cpp) +[import:34-52 lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:59-83, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -189,7 +189,7 @@ In this case, the first node visited is at the bottom of the tree and moves up t {% sample lang="st" %} [import:36-49, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:24-38, lang:"go"](code/golang/treetraversal.go) +[import:24-38, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:346-396, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -221,7 +221,7 @@ In code, it looks like this: {% sample lang="jl" %} [import:45-56, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:55-70, lang:"cpp"](code/c++/tree_example.cpp) +[import:55-70, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:85-98, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -249,7 +249,7 @@ In code, it looks like this: {% sample lang="st" %} [import:47-58, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:40-49, lang:"go"](code/golang/treetraversal.go) +[import:40-49, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:398-445, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -274,7 +274,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="jl" %} [import:58-69, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import:73-86, lang:"cpp"](code/c++/tree_example.cpp) +[import:73-86, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} [import:100-113, lang:"csharp"](code/csharp/Tree.cs) {% sample lang="c" %} @@ -302,7 +302,7 @@ And this is exactly what Breadth-First Search (BFS) does! On top of that, it can {% sample lang="st" %} [import:60-71, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import:51-60, lang:"go"](code/golang/treetraversal.go) +[import:51-60, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import:447-498, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} @@ -328,7 +328,7 @@ Here is a video describing tree traversal: {% sample lang="jl" %} [import, lang:"julia"](code/julia/Tree.jl) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/tree_example.cpp) +[import, lang:"cpp"](code/cpp/tree_example.cpp) {% sample lang="cs" %} ##### Tree.cs [import, lang:"csharp"](code/csharp/Tree.cs) @@ -366,7 +366,7 @@ The code snippets were taken from this [Scratch project](https://scratch.mit.edu {% sample lang="st" %} [import, lang:"smalltalk"](code/smalltalk/tree_traversal.st) {% sample lang="go" %} -[import, lang:"go"](code/golang/treetraversal.go) +[import, lang:"go"](code/go/treetraversal.go) {% sample lang="asm-x64" %} [import, lang:"asm-x64"](code/asm-x64/tree_traversal.s) {% sample lang="emojic" %} diff --git a/contents/verlet_integration/code/c++/verlet.cpp b/contents/verlet_integration/code/cpp/verlet.cpp similarity index 100% rename from contents/verlet_integration/code/c++/verlet.cpp rename to contents/verlet_integration/code/cpp/verlet.cpp diff --git a/contents/verlet_integration/code/golang/verlet.go b/contents/verlet_integration/code/go/verlet.go similarity index 100% rename from contents/verlet_integration/code/golang/verlet.go rename to contents/verlet_integration/code/go/verlet.go diff --git a/contents/verlet_integration/verlet_integration.md b/contents/verlet_integration/verlet_integration.md index 08fe4a4b3..80d719bef 100644 --- a/contents/verlet_integration/verlet_integration.md +++ b/contents/verlet_integration/verlet_integration.md @@ -33,7 +33,7 @@ Here is what it looks like in code: {% sample lang="jl" %} [import:1-13, lang:"julia"](code/julia/verlet.jl) {% sample lang="cpp" %} -[import:9-22, lang:"cpp"](code/c++/verlet.cpp) +[import:9-22, lang:"cpp"](code/cpp/verlet.cpp) {% sample lang="c" %} [import:3-14, lang:"c"](code/c/verlet.c) {% sample lang="java" %} @@ -53,7 +53,7 @@ Here is what it looks like in code: {% sample lang="ruby" %} [import:1-14, lang="ruby"](code/ruby/verlet.rb) {% sample lang="go" %} -[import:5-16, lang:"go"](code/golang/verlet.go) +[import:5-16, lang:"go"](code/go/verlet.go) {% sample lang="asm-x64" %} [import:18-42, lang:"asm-x64"](code/asm-x64/verlet.s) {% sample lang="kotlin" %} @@ -82,7 +82,7 @@ However, the error for this is $$\mathcal{O}(\Delta t)$$, which is quite poor, b {% sample lang="jl" %} [import:15-31, lang:"julia"](code/julia/verlet.jl) {% sample lang="cpp" %} -[import:24-41, lang:"cpp"](code/c++/verlet.cpp) +[import:24-41, lang:"cpp"](code/cpp/verlet.cpp) {% sample lang="c" %} [import:16-31, lang:"c"](code/c/verlet.c) {% sample lang="java" %} @@ -102,7 +102,7 @@ However, the error for this is $$\mathcal{O}(\Delta t)$$, which is quite poor, b {% sample lang="ruby" %} [import:16-32, lang="ruby"](code/ruby/verlet.rb) {% sample lang="go" %} -[import:18-30, lang:"go"](code/golang/verlet.go) +[import:18-30, lang:"go"](code/go/verlet.go) {% sample lang="asm-x64" %} [import:44-71, lang:"asm-x64"](code/asm-x64/verlet.s) {% sample lang="kotlin" %} @@ -145,7 +145,7 @@ Here is the velocity Verlet method in code: {% sample lang="jl" %} [import:33-45, lang:"julia"](code/julia/verlet.jl) {% sample lang="cpp" %} -[import:43-54, lang:"cpp"](code/c++/verlet.cpp) +[import:43-54, lang:"cpp"](code/cpp/verlet.cpp) {% sample lang="c" %} [import:33-43, lang:"c"](code/c/verlet.c) {% sample lang="java" %} @@ -165,7 +165,7 @@ Here is the velocity Verlet method in code: {% sample lang="ruby" %} [import:34-46, lang="ruby"](code/ruby/verlet.rb) {% sample lang="go" %} -[import:32-42, lang:"go"](code/golang/verlet.go) +[import:32-42, lang:"go"](code/go/verlet.go) {% sample lang="asm-x64" %} [import:73-101, lang:"asm-x64"](code/asm-x64/verlet.s) {% sample lang="kotlin" %} @@ -194,7 +194,7 @@ Both of these methods work simply by iterating timestep-by-timestep and can be w {% sample lang="jl" %} [import, lang:"julia"](code/julia/verlet.jl) {% sample lang="cpp" %} -[import, lang:"cpp"](code/c++/verlet.cpp) +[import, lang:"cpp"](code/cpp/verlet.cpp) {% sample lang="c" %} [import, lang:"c"](code/c/verlet.c) {% sample lang="java" %} @@ -214,7 +214,7 @@ Both of these methods work simply by iterating timestep-by-timestep and can be w {% sample lang="ruby" %} [import, lang="ruby"](code/ruby/verlet.rb) {% sample lang="go" %} -[import, lang:"go"](code/golang/verlet.go) +[import, lang:"go"](code/go/verlet.go) {% sample lang="asm-x64" %} [import, lang:"asm-x64"](code/asm-x64/verlet.s) {% sample lang="kotlin" %} From 4bc3003ab6d53e7c3d08e13e73366f41c60306b4 Mon Sep 17 00:00:00 2001 From: Fabus1184 Date: Sun, 7 Nov 2021 18:09:10 +0100 Subject: [PATCH 068/146] Fixed #917 (#922) --- contents/euclidean_algorithm/code/lolcode/euclid.lol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contents/euclidean_algorithm/code/lolcode/euclid.lol b/contents/euclidean_algorithm/code/lolcode/euclid.lol index 418851107..28e3230e3 100644 --- a/contents/euclidean_algorithm/code/lolcode/euclid.lol +++ b/contents/euclidean_algorithm/code/lolcode/euclid.lol @@ -24,7 +24,7 @@ HAI 1.2 HOW IZ I UKLIDSUP YR NUM1 AN YR NUM2 NUM1 R I IZ ABZ YR NUM1 MKAY - NUM2 R EI IZ ABZ YR NUM2 MKAY + NUM2 R I IZ ABZ YR NUM2 MKAY IM IN YR LOOP BOTH SAEM NUM1 AN NUM2, O RLY? @@ -44,4 +44,4 @@ HAI 1.2 VISIBLE CHECK1 VISIBLE CHECK2 -KTHXBYE \ No newline at end of file +KTHXBYE From be2f97d6c26354b3e2dd58a0d7d2343418c45abd Mon Sep 17 00:00:00 2001 From: James Schloss Date: Sun, 7 Nov 2021 20:40:30 +0100 Subject: [PATCH 069/146] removing Euler and adjacent chapters (#923) * removing Euler and adjacent chapters * Revert "removing Euler and adjacent chapters" This reverts commit 4293e9d4e66e02b77ac1d18b0212705a5cb7418c. * just removing chapter from summary --- SUMMARY.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index d76af219d..e41ba39d4 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -32,8 +32,6 @@ * [FFT](contents/cooley_tukey/cooley_tukey.md) * [Decision Problems](contents/decision_problems/decision_problems.md) * [Stable Marriage Problem](contents/stable_marriage_problem/stable_marriage_problem.md) -* [Differential Equation Solvers](contents/differential_equations/differential_equations.md) - * [Forward Euler Method](contents/forward_euler_method/forward_euler_method.md) * [Physics Solvers](contents/physics_solvers/physics_solvers.md) * [Verlet Integration](contents/verlet_integration/verlet_integration.md) * [Quantum Systems](contents/quantum_systems/quantum_systems.md) From 2529d2322f62283b41f2f155e1fc5c15adfb4497 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 8 Nov 2021 04:39:46 +0100 Subject: [PATCH 070/146] Add setup for devcontainer for Piet (#918) Co-authored-by: Nicholas Tindle --- .devcontainer/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 695b0ffbf..4d7e2a736 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -49,8 +49,7 @@ ENV PATH=$PATH:/usr/local/kotlinc/bin ## Use: https://github.com/justinmeza/lci # Setup Piet -## Use: https://github.com/boothby/repiet - +RUN pip install repiet # Setup Matlab # ?????? This is a licensed language??? From d440c5da46bea8e29ff4531349c3e1921c7b16d0 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 8 Nov 2021 04:43:59 +0100 Subject: [PATCH 071/146] Add devcontainer setup for lolcode (#916) Co-authored-by: Nicholas Tindle --- .devcontainer/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 4d7e2a736..6e8be7fc6 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,7 +6,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} # [Optional] Uncomment this section to install additional OS packages. RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk rustc libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch libfftw3-dev + && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk rustc libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch libfftw3-dev cmake # Setup Crystal RUN echo 'deb http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_20.04/ /' | sudo tee /etc/apt/sources.list.d/devel:languages:crystal.list @@ -46,7 +46,8 @@ RUN unzip /usr/local/kotlinc.zip ENV PATH=$PATH:/usr/local/kotlinc/bin # Setup lolcode -## Use: https://github.com/justinmeza/lci +RUN git clone https://github.com/justinmeza/lci.git ~/lolcode && cd ~/lolcode && mkdir build && cd build && cmake .. && make -B +ENV PATH=$PATH:~/lolcode/build # Setup Piet RUN pip install repiet From b115149b8c979ec8ba9482182c0a92b96e31e6ea Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 8 Nov 2021 06:33:44 +0100 Subject: [PATCH 072/146] Add devcontainer setup for whitespace (#914) * Add devcontainer setup for VimL/Vim script * Add devcontainer setup for whitespace Co-authored-by: Nicholas Tindle --- .devcontainer/Dockerfile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6e8be7fc6..adb7a8867 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -86,7 +86,8 @@ ENV PATH=$PATH:~/swift/usr/bin RUN export DEBIAN_FRONTEND=noninteractive && apt-get -y install --no-install-recommends vim # Setup whitespace -## ? +RUN mkdir -p ~/whitespace && git clone https://github.com/wspace/whitespace-haskell ~/whitespace && cd ~/whitespace && make -B +ENV PATH=$PATH:~/whitespace # Setup Elm RUN mkdir -p ~/elm && curl -L -o ~/elm/elm.gz https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz && \ @@ -98,11 +99,11 @@ RUN mkdir -p ~/vlang && wget https://github.com/vlang/v/releases/download/weekly unzip ~/vlang/vlang.zip -d ~/vlang ENV PATH=$PATH:~/vlang/v -# Install the packages that needed extra help -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket +# # Install the packages that needed extra help +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket -RUN pip install wheel matplotlib numpy coconut scons +# RUN pip install wheel matplotlib numpy coconut scons -RUN sudo sh -c 'npm install -g typescript' +# RUN sudo sh -c 'npm install -g typescript' From b0c83073fc6b79b78f3ec58a5b867141f8d519bd Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Mon, 8 Nov 2021 00:06:05 -0600 Subject: [PATCH 073/146] Fix-devcontainer-commented-out-steps (#925) * Add devcontainer setup for VimL/Vim script * Add devcontainer setup for whitespace * fix commented out dockerfile steps --- .devcontainer/Dockerfile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index adb7a8867..c61f5f670 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -99,11 +99,12 @@ RUN mkdir -p ~/vlang && wget https://github.com/vlang/v/releases/download/weekly unzip ~/vlang/vlang.zip -d ~/vlang ENV PATH=$PATH:~/vlang/v -# # Install the packages that needed extra help -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket +# Install the packages that needed extra help +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends crystal dart nim powershell scala dotnet-sdk-5.0 r-base racket + -# RUN pip install wheel matplotlib numpy coconut scons +RUN pip install wheel matplotlib numpy coconut scons -# RUN sudo sh -c 'npm install -g typescript' +RUN sudo sh -c 'npm install -g typescript' From 71e7bde8c5213e36cc771c4408cc582c93f94528 Mon Sep 17 00:00:00 2001 From: James Schloss Date: Mon, 8 Nov 2021 17:52:00 +0200 Subject: [PATCH 074/146] adding a nojekyll file (#926) --- .nojekyll | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .nojekyll diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb From e016f4e77863b75717c2a44b136e34aa3374cfd6 Mon Sep 17 00:00:00 2001 From: PeanutbutterWarrior <50717143+PeanutbutterWarrior@users.noreply.github.com> Date: Thu, 11 Nov 2021 15:12:11 +0000 Subject: [PATCH 075/146] Force SCons to use GCC when building .c files (#928) --- SConstruct | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index df000f732..bf9a15979 100644 --- a/SConstruct +++ b/SConstruct @@ -8,8 +8,14 @@ Currently, the aim is to provide a way to compile or copy the implementation fil To run the compilation for all implmeentations in one language, e.g. Rust, run the command `scons build/c`, and the resulting executables will be available in the `cuild/c` directory, each in their respective algorithm directory, containing the executable.""" from pathlib import Path +import os -env = Environment() +env = Environment(ENV={'PATH': os.environ['PATH']}) + +env['CC'] = 'gcc' +for tool in ['gcc','gnulink']: + env.Tool(tool) +env['CCFLAGS'] = '' # Add other languages here when you want to add language targets languages = ['c'] From edffc2d59e546618d38e2b0ddcb2a3a50a57379e Mon Sep 17 00:00:00 2001 From: PeanutbutterWarrior <50717143+PeanutbutterWarrior@users.noreply.github.com> Date: Thu, 11 Nov 2021 22:21:52 +0000 Subject: [PATCH 076/146] Improve SCons to use default files (#931) --- SConscript | 10 ------- SConstruct | 29 +++++++++++++++++-- contents/IFS/code/c/SConscript | 6 ---- contents/barnsley/code/c/SConscript | 6 ---- contents/computus/code/c/SConscript | 6 ---- .../euclidean_algorithm/code/c/SConscript | 6 ---- contents/flood_fill/code/c/SConscript | 6 ---- .../gaussian_elimination/code/c/SConscript | 6 ---- contents/huffman_encoding/code/c/SConscript | 6 ---- contents/jarvis_march/code/c/SConscript | 6 ---- .../monte_carlo_integration/code/c/SConscript | 6 ---- .../stable_marriage_problem/code/c/SConscript | 6 ---- contents/thomas_algorithm/code/c/SConscript | 6 ---- contents/tree_traversal/code/c/SConscript | 6 ---- contents/verlet_integration/code/c/SConscript | 6 ---- sconscripts/c_SConscript | 6 ++++ 16 files changed, 32 insertions(+), 91 deletions(-) delete mode 100644 SConscript delete mode 100644 contents/IFS/code/c/SConscript delete mode 100644 contents/barnsley/code/c/SConscript delete mode 100644 contents/computus/code/c/SConscript delete mode 100644 contents/euclidean_algorithm/code/c/SConscript delete mode 100644 contents/flood_fill/code/c/SConscript delete mode 100644 contents/gaussian_elimination/code/c/SConscript delete mode 100644 contents/huffman_encoding/code/c/SConscript delete mode 100644 contents/jarvis_march/code/c/SConscript delete mode 100644 contents/monte_carlo_integration/code/c/SConscript delete mode 100644 contents/stable_marriage_problem/code/c/SConscript delete mode 100644 contents/thomas_algorithm/code/c/SConscript delete mode 100644 contents/tree_traversal/code/c/SConscript delete mode 100644 contents/verlet_integration/code/c/SConscript create mode 100644 sconscripts/c_SConscript diff --git a/SConscript b/SConscript deleted file mode 100644 index be18b33d3..000000000 --- a/SConscript +++ /dev/null @@ -1,10 +0,0 @@ -from pathlib import Path - -Import('*') - -for p in Path('contents').iterdir(): - if (q := (p / 'code')).exists(): - for path in q.iterdir(): - if path.stem in languages: - env.SConscript(path / 'SConscript', exports='env', - must_exist=0) diff --git a/SConstruct b/SConstruct index bf9a15979..b5f5cdd11 100644 --- a/SConstruct +++ b/SConstruct @@ -5,7 +5,7 @@ This provides Builder objects for each of the language implementations in the AA Currently, the aim is to provide a way to compile or copy the implementation files to the build directory, as well as to provide ways to run them and capture their output. -To run the compilation for all implmeentations in one language, e.g. Rust, run the command `scons build/c`, and the resulting executables will be available in the `cuild/c` directory, each in their respective algorithm directory, containing the executable.""" +To run the compilation for all implementations in one language, e.g. C, run the command `scons build/c`, and the resulting executables will be available in the `build/c` directory, each in their respective algorithm directory, containing the executable.""" from pathlib import Path import os @@ -18,9 +18,32 @@ for tool in ['gcc','gnulink']: env['CCFLAGS'] = '' # Add other languages here when you want to add language targets -languages = ['c'] +# Put 'name_of_language_directory' : 'file_extension' +languages = {'c': 'c'} env.C = env.Program -SConscript('SConscript', exports='env languages') +Export('env') + +sconscripts = [] +files_to_compile = {language: [] for language in languages} + +for chapter_dir in Path.cwd().joinpath('contents').iterdir(): + if (code_dir := (chapter_dir / 'code')).exists(): + for path in code_dir.iterdir(): + if path.stem in languages: + # Check for overriding sconscript + if (sconscript_path := path / 'SConscript').exists(): + sconscripts.append(sconscript_path) + SConscript(sconscript_path, exports='env') + else: + files_to_compile[path.stem].extend(path.glob(f'*.{languages[path.stem]}')) + +sconscript_dir_path = Path('sconscripts') +for language, files in files_to_compile.items(): + if files: + if (sconscript_path := sconscript_dir_path / f"{language}_SConscript").exists(): + SConscript(sconscript_path, exports = {'files_to_compile': files}) + else: + print(f'{language} file found at {files[0]}, but no sconscript file is present ') diff --git a/contents/IFS/code/c/SConscript b/contents/IFS/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/IFS/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/barnsley/code/c/SConscript b/contents/barnsley/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/barnsley/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/computus/code/c/SConscript b/contents/computus/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/computus/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/euclidean_algorithm/code/c/SConscript b/contents/euclidean_algorithm/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/euclidean_algorithm/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/flood_fill/code/c/SConscript b/contents/flood_fill/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/flood_fill/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/gaussian_elimination/code/c/SConscript b/contents/gaussian_elimination/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/gaussian_elimination/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/huffman_encoding/code/c/SConscript b/contents/huffman_encoding/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/huffman_encoding/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/jarvis_march/code/c/SConscript b/contents/jarvis_march/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/jarvis_march/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/monte_carlo_integration/code/c/SConscript b/contents/monte_carlo_integration/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/monte_carlo_integration/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/stable_marriage_problem/code/c/SConscript b/contents/stable_marriage_problem/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/stable_marriage_problem/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/thomas_algorithm/code/c/SConscript b/contents/thomas_algorithm/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/thomas_algorithm/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/tree_traversal/code/c/SConscript b/contents/tree_traversal/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/tree_traversal/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/contents/verlet_integration/code/c/SConscript b/contents/verlet_integration/code/c/SConscript deleted file mode 100644 index fd696f9ce..000000000 --- a/contents/verlet_integration/code/c/SConscript +++ /dev/null @@ -1,6 +0,0 @@ -Import('*') -from pathlib import Path - -dirname = Path.cwd().parents[1].stem - -env.C(f'#/build/c/{dirname}', Glob('*.c')) diff --git a/sconscripts/c_SConscript b/sconscripts/c_SConscript new file mode 100644 index 000000000..a0cbffd95 --- /dev/null +++ b/sconscripts/c_SConscript @@ -0,0 +1,6 @@ +Import('files_to_compile env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + env.C(f'#/build/c/{chapter_name}', str(file)) From a9c5f89c45a5f3fff7bc2567f61dc8402256e2e6 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Tue, 16 Nov 2021 01:01:15 +0100 Subject: [PATCH 077/146] Fix devcontainer for Kotlin (#930) --- .devcontainer/Dockerfile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c61f5f670..d6ecdfc45 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -40,10 +40,9 @@ ENV PATH=$PATH:~/dlang/dmd-$DLANG_VERSION/linux/bin64/ RUN sudo sh -c 'wget -c https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local' ENV PATH=$PATH:/usr/local/go/bin -# Setup Kotlin (doesnt unzip right maybe?) -RUN sudo sh -c 'wget -c https://github.com/JetBrains/kotlin/releases/download/v1.5.30/kotlin-compiler-1.5.30.zip -O /usr/local/kotlinc.zip' -RUN unzip /usr/local/kotlinc.zip -ENV PATH=$PATH:/usr/local/kotlinc/bin +# Setup Kotlin +RUN mkdir -p ~/kotlin && wget -c https://github.com/JetBrains/kotlin/releases/download/v1.5.30/kotlin-compiler-1.5.30.zip -O ~/kotlin/kotlinc.zip && cd ~/kotlin && unzip kotlinc.zip +ENV PATH=$PATH:~/kotlin/kotlinc/bin # Setup lolcode RUN git clone https://github.com/justinmeza/lci.git ~/lolcode && cd ~/lolcode && mkdir build && cd build && cmake .. && make -B From 41a172891493e779d0f938deaa26be59cab33140 Mon Sep 17 00:00:00 2001 From: Jie Date: Sun, 21 Nov 2021 23:09:46 +0900 Subject: [PATCH 078/146] [Haskell] Barnsley Fern (#851) * resolve conflicts * updates according to review --- contents/barnsley/barnsley.md | 12 ++++--- contents/barnsley/code/haskell/Barnsley.hs | 40 ++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 contents/barnsley/code/haskell/Barnsley.hs diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index c879d7bbd..9c353f8b4 100644 --- a/contents/barnsley/barnsley.md +++ b/contents/barnsley/barnsley.md @@ -24,7 +24,7 @@ In this chapter, I hope to provide a slightly more satisfying answer by introduc | Hutchinson Operator | Attractor | | ------------------- | --------- | -| $$\begin{align} f_1(P) &= \begin{bmatrix} 0 &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix} \\ f_2(P) &= \begin{bmatrix} 0.85 &0.04 \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_3(P) &= \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &022 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_4(P) &= \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix} \end{align}$$ | Barnsley Chaos Game | +| $$\begin{align} f_1(P) &= \begin{bmatrix} 0 &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix} \\ f_2(P) &= \begin{bmatrix} 0.85 &0.04 \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_3(P) &= \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &0.22 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix} \\ f_4(P) &= \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix} \end{align}$$ | Barnsley Chaos Game | At first glance, this set of functions looks like an incomprehensible mess of magic numbers to create a specific result, and in a sense, that is precisely correct. That said, we will go through each function and explain how it works, while also providing a simple chaos game implementation in code. @@ -54,7 +54,7 @@ Now let's hop into disecting the Barnsley fern by seeing how each transform affe | -------- | --------- | | $$f_1(P) = \begin{bmatrix} 0 &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$

This operation moves every point to a single line. |

| | $$f_2(P) = \begin{bmatrix} 0.85 &0.04 \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$

This operation moves every point up and to the right. |

| -| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &022 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$

This operation rotates every point to the left. |

| +| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &0.22 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$

This operation rotates every point to the left. |

| | $$f_4(P) = \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix}$$

This operation flips every point and rotates to the right.|

| At this stage, it *might* be clear what is going on, but it's not exactly obvious. @@ -71,7 +71,7 @@ The easiest way to make sense of this is to show the operations on the Barnsley | -------- | --------- | | $$f_1(P) = \begin{bmatrix} 0 &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$ |
| | $$f_2(P) = \begin{bmatrix} 0.85 &0.04 \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ |
| -| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &022 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ |
| +| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &0.22 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ |
| | $$f_4(P) = \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix}$$ |
| Here, the self-similar nature of the fern becomes apparent. @@ -86,7 +86,7 @@ To account for this, each function is also given a probability of being chosen: | -------- | ----------- | | $$f_1(P) = \begin{bmatrix} 0 &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$ | 0.01 | | $$f_2(P) = \begin{bmatrix} 0.85 &0.04 \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ | 0.85 | -| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &022 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ | 0.07 | +| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &0.22 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$ | 0.07 | | $$f_4(P) = \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0.44 \end{bmatrix}$$ | 0.07 | ## Playing around a bit... @@ -98,7 +98,7 @@ Here are a few examples of ferns that can be generated by modifying constituent | -------- | --------- | | $$f_1(P) = \begin{bmatrix} \tau &0 \\ 0 &0.16 \end{bmatrix}P + \begin{bmatrix} 0 \\ 0 \end{bmatrix}$$

where $$-0.5 < \tau < 0.5 $$

Turning stems to leaves |

| | $$f_2(P) = \begin{bmatrix} 0.85 & \tau \\ -0.04 &0.85 \end{bmatrix}P + \begin{bmatrix} 0 \\ 1.6 \end{bmatrix}$$

where $$ -0.01 < \tau < 0.09 $$

Changing fern tilt |

| -| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &022 \end{bmatrix}P + \begin{bmatrix} \tau \\ 1.6 \end{bmatrix}$$

where $$-0.5 < \tau < 0.5$$

Plucking left leaves |

| +| $$f_3(P) = \begin{bmatrix} 0.2 &-0.26 \\ 0.23 &0.22 \end{bmatrix}P + \begin{bmatrix} \tau \\ 1.6 \end{bmatrix}$$

where $$-0.5 < \tau < 0.5$$

Plucking left leaves |

| | $$f_4(P) = \begin{bmatrix} -0.15 &0.28 \\ 0.26 &0.24 \end{bmatrix}P + \begin{bmatrix} \tau \\ 0.44 \end{bmatrix}$$

where $$-0.5 < \tau < 0.5$$

Plucking right leaves |

| As an important note: the idea of modifying a resulting image by twiddling the knobs of an affine transform is the heart of many interesting methods, including fractal image compression where a low resolution version of an image is stored along with a reconstructing function set to generate high-quality images on-the-fly {{ "fractal-compression" | cite }}{{ "saupe1994review" | cite }}. @@ -135,6 +135,8 @@ The biggest differences between the two code implementations is that the Barnsle [import, lang:"java"](code/java/Barnsley.java) {% sample lang="coco" %} [import, lang:"coconut"](code/coconut/barnsley.coco) +{% sample lang="hs" %} +[import, lang:"haskell"](code/haskell/Barnsley.hs) {% endmethod %} ### Bibliography diff --git a/contents/barnsley/code/haskell/Barnsley.hs b/contents/barnsley/code/haskell/Barnsley.hs new file mode 100644 index 000000000..bf7024200 --- /dev/null +++ b/contents/barnsley/code/haskell/Barnsley.hs @@ -0,0 +1,40 @@ +import Data.Array (Array, bounds, elems, listArray, (!)) +import Data.List (intercalate) +import System.Random + +data Point = Point Double Double + +chaosGame :: RandomGen g => g -> Int -> Array Int (Double, (Point -> Point)) -> [Point] +chaosGame g n hutchinson = take n points + where + (x, g') = random g + (y, g'') = random g' + + cumulProbabilities = scanl1 (+) $ map fst $ elems hutchinson + to_choice x = length $ takeWhile (x >) cumulProbabilities + + picks = map to_choice $ randomRs (0, 1) g'' + step = fmap snd hutchinson + + points = Point x y : zipWith (step !) picks points + +affine :: (Double, Double, Double, Double) -> (Double, Double) -> Point -> Point +affine (xx, xy, yx, yy) (a, b) (Point x y) = Point (a + xx * x + xy * y) (b + yx * x + yy * y) + +showPoint :: Point -> String +showPoint (Point x y) = show x ++ "\t" ++ show y + +main :: IO () +main = do + g <- newStdGen + let barnsley = + listArray + (0, 3) + [ (0.01, affine (0, 0, 0, 0.16) (0, 0)), + (0.85, affine (0.85, 0.04, -0.04, 0.85) (0, 1.6)), + (0.07, affine (0.2, -0.26, 0.23, 0.22) (0, 1.6)), + (0.07, affine (-0.15, 0.28, 0.26, 0.24) (0, 0.44)) + ] + points = chaosGame g 100000 barnsley + + writeFile "out.dat" $ intercalate "\n" $ map showPoint points From 866581ecc7a46a2e235e2e9e42db89046bcd4385 Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Mon, 22 Nov 2021 10:29:01 -0600 Subject: [PATCH 079/146] feat: add publish dockerfile (#938) --- .devcontainer/devcontainer.json | 2 +- .github/workflows/publish_container.yml | 17 +++++++++++++++++ .devcontainer/Dockerfile => Dockerfile | 0 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish_container.yml rename .devcontainer/Dockerfile => Dockerfile (100%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d09155c0b..e9d6bbefa 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ { "name": "Ubuntu", "build": { - "dockerfile": "Dockerfile", + "dockerfile": "../Dockerfile", // Update 'VARIANT' to pick an Ubuntu version: focal, bionic "args": { "VARIANT": "focal" } }, diff --git a/.github/workflows/publish_container.yml b/.github/workflows/publish_container.yml new file mode 100644 index 000000000..84759dbdf --- /dev/null +++ b/.github/workflows/publish_container.yml @@ -0,0 +1,17 @@ +name: Publish Docker +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: algorithm-archivists/aaa-langs + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/Dockerfile similarity index 100% rename from .devcontainer/Dockerfile rename to Dockerfile From 465e1e859ee9351209ae1a8f611492614a6918a2 Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Mon, 22 Nov 2021 19:07:28 +0100 Subject: [PATCH 080/146] Added C++ compilation (#939) --- SConstruct | 5 ++++- contents/split-operator_method/code/cpp/SConscript | 6 ++++++ sconscripts/cpp_SConscript | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 contents/split-operator_method/code/cpp/SConscript create mode 100644 sconscripts/cpp_SConscript diff --git a/SConstruct b/SConstruct index b5f5cdd11..c93744156 100644 --- a/SConstruct +++ b/SConstruct @@ -16,12 +16,15 @@ env['CC'] = 'gcc' for tool in ['gcc','gnulink']: env.Tool(tool) env['CCFLAGS'] = '' +env['CXXFLAGS'] = '-std=c++17' # Add other languages here when you want to add language targets # Put 'name_of_language_directory' : 'file_extension' -languages = {'c': 'c'} +languages = {'c': 'c', 'cpp': 'cpp'} env.C = env.Program +env.CPlusPlus = env.Program + Export('env') diff --git a/contents/split-operator_method/code/cpp/SConscript b/contents/split-operator_method/code/cpp/SConscript new file mode 100644 index 000000000..a25ed8c91 --- /dev/null +++ b/contents/split-operator_method/code/cpp/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.CPlusPlus(f'#/build/cpp/{dirname}', Glob('*.cpp'), LIBS=['m', 'fftw3']) diff --git a/sconscripts/cpp_SConscript b/sconscripts/cpp_SConscript new file mode 100644 index 000000000..a30e08652 --- /dev/null +++ b/sconscripts/cpp_SConscript @@ -0,0 +1,6 @@ +Import('files_to_compile env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + env.CPlusPlus(f'#/build/cpp/{chapter_name}', str(file)) From edbf50bfaeba82f84aa14f51cd26ef0d29dbd32b Mon Sep 17 00:00:00 2001 From: James Schloss Date: Mon, 22 Nov 2021 19:16:35 +0100 Subject: [PATCH 081/146] attempt at output standardization for approximate counting (#913) * attempt at output standardization for approximate counting * further standardization --- .../code/c/approximate_counting.c | 15 +++++++---- .../code/cpp/approximate_counting.cpp | 10 +++---- .../code/julia/approximate_counting.jl | 26 ++++++++++++------- .../code/python/approximate_counting.py | 9 ++++--- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/contents/approximate_counting/code/c/approximate_counting.c b/contents/approximate_counting/code/c/approximate_counting.c index da44334a7..2be6ffaf8 100644 --- a/contents/approximate_counting/code/c/approximate_counting.c +++ b/contents/approximate_counting/code/c/approximate_counting.c @@ -63,19 +63,24 @@ void test_approximation_count(size_t n_trials, size_t n_items, double a, } double avg = sum / n_trials; - assert(fabs((avg - n_items) / n_items) < threshold); + if (fabs((avg - n_items) / n_items) < threshold){ + printf("passed\n"); + } + else{ + printf("failed\n"); + } } int main() { srand(time(NULL)); - printf("Counting Tests, 100 trials\n"); - printf("testing 1000, a = 30, 10%% error\n"); + printf("[#]\nCounting Tests, 100 trials\n"); + printf("[#]\ntesting 1,000, a = 30, 10%% error\n"); test_approximation_count(100, 1000, 30, 0.1); - printf("testing 12345, a = 10, 10%% error\n"); + printf("[#]\ntesting 12,345, a = 10, 10%% error\n"); test_approximation_count(100, 12345, 10, 0.1); - printf("testing 222222, a = 0.5, 20%% error\n"); + printf("[#]\ntesting 222,222, a = 0.5, 20%% error\n"); test_approximation_count(100, 222222, 0.5, 0.2); return 0; diff --git a/contents/approximate_counting/code/cpp/approximate_counting.cpp b/contents/approximate_counting/code/cpp/approximate_counting.cpp index 53f4641af..1ee2790b7 100644 --- a/contents/approximate_counting/code/cpp/approximate_counting.cpp +++ b/contents/approximate_counting/code/cpp/approximate_counting.cpp @@ -55,17 +55,17 @@ auto test_approximate_count( for (auto i = 0; i < n_trials; ++i) sum += approximate_count(n_items, a); const auto avg = sum / n_trials; - return std::abs((avg - n_items) / n_items) < threshold ? "pass" : "fail"; + return std::abs((avg - n_items) / n_items) < threshold ? "passed" : "failed"; } int main() { - std::cout << "Counting Tests, 100 trials\n"; + std::cout << "[#]\nCounting Tests, 100 trials\n"; - std::cout << "testing 1,000, a = 30, 10% error " + std::cout << "[#]\ntesting 1,000, a = 30, 10% error \n" << test_approximate_count(100, 1000, 30, 0.1) << "\n"; - std::cout << "testing 12,345, a = 10, 10% error " + std::cout << "[#]\ntesting 12,345, a = 10, 10% error \n" << test_approximate_count(100, 12345, 10, 0.1) << "\n"; // Note : with a lower a, we need more trials, so a higher % error here. - std::cout << "testing 222,222, a = 0.5, 20% error " + std::cout << "[#]\ntesting 222,222, a = 0.5, 20% error \n" << test_approximate_count(100, 222222, 0.5, 0.2) << "\n"; } diff --git a/contents/approximate_counting/code/julia/approximate_counting.jl b/contents/approximate_counting/code/julia/approximate_counting.jl index c6cf3b223..24c9f0fb6 100644 --- a/contents/approximate_counting/code/julia/approximate_counting.jl +++ b/contents/approximate_counting/code/julia/approximate_counting.jl @@ -47,15 +47,21 @@ function test_approximate_count(n_trials, n_items, a, threshold) avg = sum(samples)/n_trials - @test (abs((avg - n_items) / n_items) < threshold) + if (abs((avg - n_items) / n_items) < threshold) + println("passed") + else + println("failed") + end end -@testset "Counting Tests, 100 trials" begin - println("testing 1,000, a = 30, 10% error") - test_approximate_count(100, 1000, 30, 0.1) - println("testing 12,345, a = 10, 10% error") - test_approximate_count(100, 12345, 10, 0.1) - # Note: with a lower a, we need more trials, so a higher % error here. - println("testing 222,222, a = 0.5, 20% error") - test_approximate_count(100, 222222, 0.5, 0.2) -end +println("[#]\nCounting Tests, 100 trials") + +println("[#]\ntesting 1,000, a = 30, 10% error") +test_approximate_count(100, 1000, 30, 0.1) + +println("[#]\ntesting 12,345, a = 10, 10% error") +test_approximate_count(100, 12345, 10, 0.1) + +# Note: with a lower a, we need more trials, so a higher % error here. +println("[#]\ntesting 222,222, a = 0.5, 20% error") +test_approximate_count(100, 222222, 0.5, 0.2) diff --git a/contents/approximate_counting/code/python/approximate_counting.py b/contents/approximate_counting/code/python/approximate_counting.py index 0088debcc..a8381ffe8 100644 --- a/contents/approximate_counting/code/python/approximate_counting.py +++ b/contents/approximate_counting/code/python/approximate_counting.py @@ -40,10 +40,13 @@ def test_approximate_count(n_trials, n_items, a, threshold): if abs((avg - n_items)/n_items) < threshold: print("passed") + else: + print("failed") -print("testing 1,000, a = 30, 10% error") +print("[#]\nCounting Tests, 100 trials") +print("[#]\ntesting 1,000, a = 30, 10% error") test_approximate_count(100, 1000, 30, 0.1) -print("testing 12,345, a = 10, 10% error") +print("[#]\ntesting 12,345, a = 10, 10% error") test_approximate_count(100, 12345, 10, 0.1) -print("testing 222,222, a = 0.5, 20% error") +print("[#]\ntesting 222,222, a = 0.5, 20% error") test_approximate_count(100, 222222, 0.5, 0.2) From 9d9e1cb232a9165573773fd1dd6baa9455c38302 Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Sun, 28 Nov 2021 15:35:30 +0100 Subject: [PATCH 082/146] Added x64 assembly compilation (#940) --- SConstruct | 15 ++++++++------- contents/cooley_tukey/code/asm-x64/SConscript | 6 ++++++ .../forward_euler_method/code/asm-x64/SConscript | 6 ++++++ sconscripts/asm-x64_SConscript | 6 ++++++ 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 contents/cooley_tukey/code/asm-x64/SConscript create mode 100644 contents/forward_euler_method/code/asm-x64/SConscript create mode 100644 sconscripts/asm-x64_SConscript diff --git a/SConstruct b/SConstruct index c93744156..93354e152 100644 --- a/SConstruct +++ b/SConstruct @@ -10,21 +10,21 @@ To run the compilation for all implementations in one language, e.g. C, run the from pathlib import Path import os -env = Environment(ENV={'PATH': os.environ['PATH']}) +env = Environment(ENV={'PATH': os.environ['PATH']}, + tools=['gcc', 'gnulink', 'g++', 'gas']) + +env['ASFLAGS'] = '--64' -env['CC'] = 'gcc' -for tool in ['gcc','gnulink']: - env.Tool(tool) env['CCFLAGS'] = '' env['CXXFLAGS'] = '-std=c++17' # Add other languages here when you want to add language targets # Put 'name_of_language_directory' : 'file_extension' -languages = {'c': 'c', 'cpp': 'cpp'} +languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's'} env.C = env.Program env.CPlusPlus = env.Program - +env.X64 = env.Program Export('env') @@ -46,7 +46,8 @@ sconscript_dir_path = Path('sconscripts') for language, files in files_to_compile.items(): if files: if (sconscript_path := sconscript_dir_path / f"{language}_SConscript").exists(): - SConscript(sconscript_path, exports = {'files_to_compile': files}) + SConscript(sconscript_path, exports = {'files_to_compile': files, + 'language': language}) else: print(f'{language} file found at {files[0]}, but no sconscript file is present ') diff --git a/contents/cooley_tukey/code/asm-x64/SConscript b/contents/cooley_tukey/code/asm-x64/SConscript new file mode 100644 index 000000000..05360fe6c --- /dev/null +++ b/contents/cooley_tukey/code/asm-x64/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.X64(f'#/build/asm-x64/{dirname}', Glob('*.s'), LIBS=['m'], LINKFLAGS='-no-pie') diff --git a/contents/forward_euler_method/code/asm-x64/SConscript b/contents/forward_euler_method/code/asm-x64/SConscript new file mode 100644 index 000000000..9322fd10c --- /dev/null +++ b/contents/forward_euler_method/code/asm-x64/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.X64(f'#/build/asm-x64/{dirname}', Glob('*.s'), LIBS='m', LINKFLAGS='-no-pie') diff --git a/sconscripts/asm-x64_SConscript b/sconscripts/asm-x64_SConscript new file mode 100644 index 000000000..caabf226f --- /dev/null +++ b/sconscripts/asm-x64_SConscript @@ -0,0 +1,6 @@ +Import('files_to_compile language env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + env.X64(f'#/build/{language}/{chapter_name}', str(file), LINKFLAGS='-no-pie') From 18eebd6277158738b1ef507037939a50749b8a70 Mon Sep 17 00:00:00 2001 From: PeanutbutterWarrior <50717143+PeanutbutterWarrior@users.noreply.github.com> Date: Sun, 28 Nov 2021 20:56:17 +0000 Subject: [PATCH 083/146] Add Rust to SCons (#945) * Add rust builder and build script * Move file to be discovered by SCons, and update Cargo.toml to reflect this * Add rustc to SCons * Add Cargo.toml files for code requiring libraries * Add cargo building when Cargo.toml is present * Fix copying fail on linux due to directory name and file name collision * Add build artifacts to SCons clean command and .gitignore * Fix Not a directory issue due to getting parent directory of a file * Remove redefinition of languages dictionary * Add rustc and cargo install to docker * Update Cooley-Tukey to use correct version of crates * Update split-operator method to use correct library versions and apply fixes from #688 --- .gitignore | 4 ++++ Dockerfile | 5 ++++- SConstruct | 13 +++++++++---- contents/barnsley/code/rust/Cargo.toml | 8 ++++++-- .../code/rust/{src/main.rs => barnsley.rs} | 0 contents/cooley_tukey/code/rust/Cargo.toml | 14 ++++++++++++++ contents/huffman_encoding/code/rust/Cargo.toml | 13 +++++++++++++ .../monte_carlo_integration/code/rust/Cargo.toml | 13 +++++++++++++ .../split-operator_method/code/rust/Cargo.toml | 13 +++++++++++++ .../split-operator_method/code/rust/split_op.rs | 5 ++--- sconscripts/rust_SConscript | 14 ++++++++++++++ 11 files changed, 92 insertions(+), 10 deletions(-) rename contents/barnsley/code/rust/{src/main.rs => barnsley.rs} (100%) create mode 100644 contents/cooley_tukey/code/rust/Cargo.toml create mode 100644 contents/huffman_encoding/code/rust/Cargo.toml create mode 100644 contents/monte_carlo_integration/code/rust/Cargo.toml create mode 100644 contents/split-operator_method/code/rust/Cargo.toml create mode 100644 sconscripts/rust_SConscript diff --git a/.gitignore b/.gitignore index 231da8ea1..4d5a431b0 100644 --- a/.gitignore +++ b/.gitignore @@ -524,3 +524,7 @@ vscode/ # SCons build directory build/ + +# Cargo artifacts +Cargo.lock +target/ diff --git a/Dockerfile b/Dockerfile index d6ecdfc45..a0808c1ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} # [Optional] Uncomment this section to install additional OS packages. RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk rustc libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch libfftw3-dev cmake + && apt-get -y install --no-install-recommends build-essential software-properties-common xz-utils g++ sbcl julia python3 python3-pip python3-dev ghc openjdk-11-jdk libssl-dev gfortran libxml2-dev libyaml-dev libgmp-dev libz-dev libncurses5 gnuplot nodejs npm lua5.3 ocaml php ruby-full gnu-smalltalk scratch libfftw3-dev cmake # Setup Crystal RUN echo 'deb http://download.opensuse.org/repositories/devel:/languages:/crystal/xUbuntu_20.04/ /' | sudo tee /etc/apt/sources.list.d/devel:languages:crystal.list @@ -72,6 +72,9 @@ RUN sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu fo RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys D9D33FCD84D82C17288BA03B3C9A6980F827E01E RUN sudo add-apt-repository 'deb http://ppa.launchpad.net/plt/racket/ubuntu focal main' +# Setup Rust +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y + # Setup Scratch ## using 1.x right now.... in future checkout snap or adobe air? diff --git a/SConstruct b/SConstruct index 93354e152..1a20bf633 100644 --- a/SConstruct +++ b/SConstruct @@ -10,17 +10,22 @@ To run the compilation for all implementations in one language, e.g. C, run the from pathlib import Path import os -env = Environment(ENV={'PATH': os.environ['PATH']}, - tools=['gcc', 'gnulink', 'g++', 'gas']) +rust_cargo_builder = Builder(action=['cargo build --bins --manifest-path $MANIFEST', + Move('$TARGET$PROGSUFFIX', '$SOURCE_DIR/target/debug/main$PROGSUFFIX')]) -env['ASFLAGS'] = '--64' +rust_rustc_builder = Builder(action='rustc $SOURCE -o $TARGET$PROGSUFFIX') + +env = Environment(ENV=os.environ, + BUILDERS={'rustc': rust_rustc_builder, 'cargo': rust_cargo_builder}, + tools=['gcc', 'gnulink', 'g++', 'gas']) env['CCFLAGS'] = '' env['CXXFLAGS'] = '-std=c++17' +env['ASFLAGS'] = '--64' # Add other languages here when you want to add language targets # Put 'name_of_language_directory' : 'file_extension' -languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's'} +languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's', 'rust': 'rs'} env.C = env.Program env.CPlusPlus = env.Program diff --git a/contents/barnsley/code/rust/Cargo.toml b/contents/barnsley/code/rust/Cargo.toml index 40780594a..52505634b 100644 --- a/contents/barnsley/code/rust/Cargo.toml +++ b/contents/barnsley/code/rust/Cargo.toml @@ -1,9 +1,13 @@ [package] -name = "rust" +name = "barnsley" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rand = "0.8.4" \ No newline at end of file +rand = "0.8.4" + +[[bin]] +path = "./barnsley.rs" +name = "main" \ No newline at end of file diff --git a/contents/barnsley/code/rust/src/main.rs b/contents/barnsley/code/rust/barnsley.rs similarity index 100% rename from contents/barnsley/code/rust/src/main.rs rename to contents/barnsley/code/rust/barnsley.rs diff --git a/contents/cooley_tukey/code/rust/Cargo.toml b/contents/cooley_tukey/code/rust/Cargo.toml new file mode 100644 index 000000000..0cba5179d --- /dev/null +++ b/contents/cooley_tukey/code/rust/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.7.3" +rustfft = "4.1.0" + +[[bin]] +path = "./fft.rs" +name = "main" \ No newline at end of file diff --git a/contents/huffman_encoding/code/rust/Cargo.toml b/contents/huffman_encoding/code/rust/Cargo.toml new file mode 100644 index 000000000..1add99ad2 --- /dev/null +++ b/contents/huffman_encoding/code/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "huffman" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.10.1" + +[[bin]] +path = "./huffman.rs" +name = "main" \ No newline at end of file diff --git a/contents/monte_carlo_integration/code/rust/Cargo.toml b/contents/monte_carlo_integration/code/rust/Cargo.toml new file mode 100644 index 000000000..17ff7f385 --- /dev/null +++ b/contents/monte_carlo_integration/code/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "montecarlo" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.4" + +[[bin]] +path = "./monte_carlo.rs" +name = "main" \ No newline at end of file diff --git a/contents/split-operator_method/code/rust/Cargo.toml b/contents/split-operator_method/code/rust/Cargo.toml new file mode 100644 index 000000000..def85c23e --- /dev/null +++ b/contents/split-operator_method/code/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "splitop" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustfft = "4.1.0" + +[[bin]] +path = "./split_op.rs" +name = "main" \ No newline at end of file diff --git a/contents/split-operator_method/code/rust/split_op.rs b/contents/split-operator_method/code/rust/split_op.rs index 7269f5148..d29e16a2e 100644 --- a/contents/split-operator_method/code/rust/split_op.rs +++ b/contents/split-operator_method/code/rust/split_op.rs @@ -1,7 +1,6 @@ -extern crate num; extern crate rustfft; -use num::complex::Complex; +use rustfft::num_complex::Complex; use rustfft::FFTplanner; use std::f64::consts::PI; use std::fs::File; @@ -95,7 +94,7 @@ fn fft(x: &mut Vec>, inverse: bool) { let mut y = vec![Complex::new(0.0_f64, 0.0_f64); x.len()]; let mut p = FFTplanner::new(inverse); let fft = p.plan_fft(x.len()); - fft.process(x, &mut y); + fft.process(x.as_mut_slice(), y.as_mut_slice()); for i in 0..x.len() { x[i] = y[i] / (x.len() as f64).sqrt(); diff --git a/sconscripts/rust_SConscript b/sconscripts/rust_SConscript new file mode 100644 index 000000000..b9cf669c7 --- /dev/null +++ b/sconscripts/rust_SConscript @@ -0,0 +1,14 @@ +Import('files_to_compile env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + if (file.parent / 'Cargo.toml').exists(): + env.cargo(target=f'#/build/rust/{chapter_name}', + source=str(file), + MANIFEST=str(file.parent / 'Cargo.toml'), + SOURCE_DIR=str(file.parent)) + env.Clean('rust', str(file.parent / 'target')) + else: + env.rustc(f'#/build/rust/{chapter_name}', str(file)) + env.Clean('rust', f'#/build/rust/{chapter_name}.pdb') From c3c0938dd13b4f8b583ec7179b3d1d49dec5d789 Mon Sep 17 00:00:00 2001 From: PeanutbutterWarrior <50717143+PeanutbutterWarrior@users.noreply.github.com> Date: Sun, 28 Nov 2021 22:19:04 +0000 Subject: [PATCH 084/146] Add Go to SCons (#947) --- SConstruct | 8 ++++++-- sconscripts/go_SConscript | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 sconscripts/go_SConscript diff --git a/SConstruct b/SConstruct index 1a20bf633..8f01fe4fe 100644 --- a/SConstruct +++ b/SConstruct @@ -15,8 +15,12 @@ rust_cargo_builder = Builder(action=['cargo build --bins --manifest-path $MANIFE rust_rustc_builder = Builder(action='rustc $SOURCE -o $TARGET$PROGSUFFIX') +go_builder = Builder(action='go build -o $TARGET$PROGSUFFIX $SOURCE') + env = Environment(ENV=os.environ, - BUILDERS={'rustc': rust_rustc_builder, 'cargo': rust_cargo_builder}, + BUILDERS={'rustc': rust_rustc_builder, + 'cargo': rust_cargo_builder, + 'Go': go_builder}, tools=['gcc', 'gnulink', 'g++', 'gas']) env['CCFLAGS'] = '' @@ -25,7 +29,7 @@ env['ASFLAGS'] = '--64' # Add other languages here when you want to add language targets # Put 'name_of_language_directory' : 'file_extension' -languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's', 'rust': 'rs'} +languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's', 'rust': 'rs', 'go': 'go'} env.C = env.Program env.CPlusPlus = env.Program diff --git a/sconscripts/go_SConscript b/sconscripts/go_SConscript new file mode 100644 index 000000000..795be1d53 --- /dev/null +++ b/sconscripts/go_SConscript @@ -0,0 +1,6 @@ +Import('files_to_compile env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + env.Go(f'#/build/go/{chapter_name}', str(file)) From 0aa53332fb7366a7a1b9f93f55d7c72126534088 Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Sun, 28 Nov 2021 23:36:08 +0100 Subject: [PATCH 085/146] Added Fortran compilation (#948) * Added Fortran compilation * Corrected a typo --- SConstruct | 12 ++++++++++-- contents/euclidean_algorithm/code/fortran/SConscript | 6 ++++++ sconscripts/fortran_SConscript | 6 ++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 contents/euclidean_algorithm/code/fortran/SConscript create mode 100644 sconscripts/fortran_SConscript diff --git a/SConstruct b/SConstruct index 8f01fe4fe..222ae14c0 100644 --- a/SConstruct +++ b/SConstruct @@ -21,7 +21,7 @@ env = Environment(ENV=os.environ, BUILDERS={'rustc': rust_rustc_builder, 'cargo': rust_cargo_builder, 'Go': go_builder}, - tools=['gcc', 'gnulink', 'g++', 'gas']) + tools=['gcc', 'gnulink', 'g++', 'gas', 'gfortran']) env['CCFLAGS'] = '' env['CXXFLAGS'] = '-std=c++17' @@ -29,11 +29,19 @@ env['ASFLAGS'] = '--64' # Add other languages here when you want to add language targets # Put 'name_of_language_directory' : 'file_extension' -languages = {'c': 'c', 'cpp': 'cpp', 'asm-x64': 's', 'rust': 'rs', 'go': 'go'} +languages = { + 'c': 'c', + 'cpp': 'cpp', + 'asm-x64': 's', + 'rust': 'rs', + 'go': 'go', + 'fortran': 'f90', +} env.C = env.Program env.CPlusPlus = env.Program env.X64 = env.Program +env.Fortran = env.Program Export('env') diff --git a/contents/euclidean_algorithm/code/fortran/SConscript b/contents/euclidean_algorithm/code/fortran/SConscript new file mode 100644 index 000000000..8146feee9 --- /dev/null +++ b/contents/euclidean_algorithm/code/fortran/SConscript @@ -0,0 +1,6 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.Fortran(f'#/build/fortran/{dirname}', 'euclidean.f90') diff --git a/sconscripts/fortran_SConscript b/sconscripts/fortran_SConscript new file mode 100644 index 000000000..df3e7fc27 --- /dev/null +++ b/sconscripts/fortran_SConscript @@ -0,0 +1,6 @@ +Import('files_to_compile env') +from pathlib import Path + +for file in files_to_compile: + chapter_name = file.parent.parent.parent.stem + env.Fortran(f'#/build/fortran/{chapter_name}', str(file)) From 71e27baca21fe5d42787c37d76763f4060ac34fb Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Mon, 29 Nov 2021 23:12:09 +0100 Subject: [PATCH 086/146] Fixing C warnings (#934) * Added warnings as errors for C/C++ code and fixed C warnings. --- SConstruct | 2 +- contents/IFS/code/c/IFS.c | 2 +- contents/barnsley/code/c/barnsley.c | 1 + contents/cooley_tukey/code/c/fft.c | 8 ++-- .../code/c/euclidean_example.c | 48 +++++++++---------- contents/flood_fill/code/c/flood_fill.c | 8 ++-- .../code/c/gaussian_elimination.c | 20 ++++---- contents/huffman_encoding/code/c/huffman.c | 4 +- .../split-operator_method/code/c/split_op.c | 6 +-- .../code/c/stable_marriage.c | 9 ++-- 10 files changed, 54 insertions(+), 54 deletions(-) diff --git a/SConstruct b/SConstruct index 222ae14c0..bd851cf0a 100644 --- a/SConstruct +++ b/SConstruct @@ -23,7 +23,7 @@ env = Environment(ENV=os.environ, 'Go': go_builder}, tools=['gcc', 'gnulink', 'g++', 'gas', 'gfortran']) -env['CCFLAGS'] = '' +env['CCFLAGS'] = '-Wall -Wextra -Werror' env['CXXFLAGS'] = '-std=c++17' env['ASFLAGS'] = '--64' diff --git a/contents/IFS/code/c/IFS.c b/contents/IFS/code/c/IFS.c index 2ba8cbdd2..99c4826be 100644 --- a/contents/IFS/code/c/IFS.c +++ b/contents/IFS/code/c/IFS.c @@ -20,7 +20,7 @@ void chaos_game(struct point *in, size_t in_n, struct point *out, struct point cur_point = {drand(), drand()}; - for (int i = 0; i < out_n; ++i) { + for (size_t i = 0; i < out_n; ++i) { out[i] = cur_point; struct point tmp = random_element(in, in_n); cur_point.x = 0.5 * (cur_point.x + tmp.x); diff --git a/contents/barnsley/code/c/barnsley.c b/contents/barnsley/code/c/barnsley.c index 17119c585..db154b777 100644 --- a/contents/barnsley/code/c/barnsley.c +++ b/contents/barnsley/code/c/barnsley.c @@ -44,6 +44,7 @@ struct matrix select_array(struct matrix *hutchinson_op, double *probabilities, } rnd -= probabilities[i]; } + return hutchinson_op[0]; } // This is a general function to simulate a chaos game diff --git a/contents/cooley_tukey/code/c/fft.c b/contents/cooley_tukey/code/c/fft.c index 90691f373..f87e12afd 100644 --- a/contents/cooley_tukey/code/c/fft.c +++ b/contents/cooley_tukey/code/c/fft.c @@ -6,7 +6,7 @@ #include #include -void fft(double complex *x, int n) { +void fft(double complex *x, size_t n) { double complex y[n]; memset(y, 0, sizeof(y)); fftw_plan p; @@ -56,8 +56,8 @@ void cooley_tukey(double complex *X, const size_t N) { } void bit_reverse(double complex *X, size_t N) { - for (int i = 0; i < N; ++i) { - int n = i; + for (size_t i = 0; i < N; ++i) { + size_t n = i; int a = i; int count = (int)log2((double)N) - 1; @@ -81,7 +81,7 @@ void iterative_cooley_tukey(double complex *X, size_t N) { bit_reverse(X, N); for (int i = 1; i <= log2((double)N); ++i) { - int stride = pow(2, i); + size_t stride = pow(2, i); double complex w = cexp(-2.0 * I * M_PI / stride); for (size_t j = 0; j < N; j += stride) { double complex v = 1.0; diff --git a/contents/euclidean_algorithm/code/c/euclidean_example.c b/contents/euclidean_algorithm/code/c/euclidean_example.c index 16b0ce9ea..12892e1aa 100644 --- a/contents/euclidean_algorithm/code/c/euclidean_example.c +++ b/contents/euclidean_algorithm/code/c/euclidean_example.c @@ -1,40 +1,40 @@ #include -#include +#include int euclid_mod(int a, int b) { - a = abs(a); - b = abs(b); + a = abs(a); + b = abs(b); - while (b != 0) { - int temp = b; - b = a % b; - a = temp; - } + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } - return a; + return a; } int euclid_sub(int a, int b) { - a = abs(a); - b = abs(b); - - while (a != b) { - if (a > b) { - a -= b; - } else { - b -= a; - } + a = abs(a); + b = abs(b); + + while (a != b) { + if (a > b) { + a -= b; + } else { + b -= a; } + } - return a; + return a; } int main() { - int check1 = euclid_mod(64 * 67, 64 * 81); - int check2 = euclid_sub(128 * 12, 128 * 77); + int check1 = euclid_mod(64 * 67, 64 * 81); + int check2 = euclid_sub(128 * 12, 128 * 77); - printf("%d\n", check1); - printf("%d\n", check2); + printf("%d\n", check1); + printf("%d\n", check2); - return 0; + return 0; } diff --git a/contents/flood_fill/code/c/flood_fill.c b/contents/flood_fill/code/c/flood_fill.c index d922412a1..03df6f1fb 100644 --- a/contents/flood_fill/code/c/flood_fill.c +++ b/contents/flood_fill/code/c/flood_fill.c @@ -25,7 +25,7 @@ int inbounds(struct point p, struct canvas c) { return (p.x < 0 || p.y < 0 || p.y >= c.max_y || p.x >= c.max_x) ? 0 : 1; } -int find_neighbors(struct canvas c, struct point p, int old_val, int new_val, +int find_neighbors(struct canvas c, struct point p, int old_val, struct point *neighbors) { int cnt = 0; struct point points[4] = { @@ -90,7 +90,7 @@ void stack_fill(struct canvas c, struct point p, int old_val, int new_val) { c.data[cur_loc.x + c.max_x * cur_loc.y] = new_val; struct point neighbors[4]; - int cnt = find_neighbors(c, cur_loc, old_val, new_val, neighbors); + int cnt = find_neighbors(c, cur_loc, old_val, neighbors); for (int i = 0; i < cnt; ++i) { stack_push(&stk, neighbors[i]); @@ -160,7 +160,7 @@ void queue_fill(struct canvas c, struct point p, int old_val, int new_val) { c.data[cur_loc.x + c.max_x * cur_loc.y] = new_val; struct point neighbors[4]; - int cnt = find_neighbors(c, cur_loc, old_val, new_val, neighbors); + int cnt = find_neighbors(c, cur_loc, old_val, neighbors); for (int i = 0; i < cnt; ++i) { enqueue(&q, neighbors[i]); @@ -181,7 +181,7 @@ void recursive_fill(struct canvas c, struct point p, int old_val, c.data[p.x + c.max_x * p.y] = new_val; struct point neighbors[4]; - int cnt = find_neighbors(c, p, old_val, new_val, neighbors); + int cnt = find_neighbors(c, p, old_val, neighbors); for (int i = 0; i < cnt; ++i) { recursive_fill(c, neighbors[i], old_val, new_val); diff --git a/contents/gaussian_elimination/code/c/gaussian_elimination.c b/contents/gaussian_elimination/code/c/gaussian_elimination.c index 0840b8076..6ca4ca70f 100644 --- a/contents/gaussian_elimination/code/c/gaussian_elimination.c +++ b/contents/gaussian_elimination/code/c/gaussian_elimination.c @@ -47,13 +47,13 @@ void gaussian_elimination(double *a, const size_t rows, const size_t cols) { } } -void back_substitution(const double *a, double *x, const size_t rows, - const size_t cols) { +void back_substitution(const double *a, double *x, const int rows, + const int cols) { for (int i = rows - 1; i >= 0; --i) { double sum = 0.0; - for (size_t j = cols - 2; j > i; --j) { + for (int j = cols - 2; j > i; --j) { sum += x[j] * a[i * cols + j]; } @@ -61,17 +61,17 @@ void back_substitution(const double *a, double *x, const size_t rows, } } -void gauss_jordan(double *a, const size_t rows, const size_t cols) { - int row = 0; +void gauss_jordan(double *a, const size_t cols) { + size_t row = 0; - for (int col = 0; col < cols - 1; ++col) { + for (size_t col = 0; col < cols - 1; ++col) { if (a[row * cols + col] != 0) { - for (int i = cols - 1; i > col - 1; --i) { + for (size_t i = cols - 1; i > col - 1; --i) { a[row * cols + i] /= a[row * cols + col]; } - for (int i = 0; i < row; ++i) { - for (int j = cols - 1; j > col - 1; --j) { + for (size_t i = 0; i < row; ++i) { + for (size_t j = cols - 1; j > col - 1; --j) { a[i * cols + j] -= a[i * cols + col] * a[row * cols + j]; } } @@ -99,7 +99,7 @@ int main() { printf("\nGauss-Jordan:\n"); - gauss_jordan((double *)a, 3, 4); + gauss_jordan((double *)a, 4); for (size_t i = 0; i < 3; ++i) { printf("["); diff --git a/contents/huffman_encoding/code/c/huffman.c b/contents/huffman_encoding/code/c/huffman.c index 571dc8c15..4f60f5da6 100644 --- a/contents/huffman_encoding/code/c/huffman.c +++ b/contents/huffman_encoding/code/c/huffman.c @@ -125,7 +125,7 @@ struct tree* generate_tree(const char* str) { } struct heap heap = { 0 }; - for (int i = 0; i < sizeof(counts) / sizeof(int); ++i) { + for (size_t i = 0; i < sizeof(counts) / sizeof(int); ++i) { if (counts[i]) { struct tree* tree = calloc(1, sizeof(struct tree)); tree->value = (char)i; @@ -211,8 +211,6 @@ char* encode(const char* input, struct tree** huffman_tree, *codebook = generate_codebook(*huffman_tree); char* result = duplicate(get_code(codebook, *input)); - int result_length = strlen(result); - int result_capacity = result_length; input += 1; diff --git a/contents/split-operator_method/code/c/split_op.c b/contents/split-operator_method/code/c/split_op.c index 0550e4ef2..ecf48e027 100644 --- a/contents/split-operator_method/code/c/split_op.c +++ b/contents/split-operator_method/code/c/split_op.c @@ -28,7 +28,7 @@ struct operators { double complex *wfc; }; -void fft(double complex *x, int n, bool inverse) { +void fft(double complex *x, size_t n, bool inverse) { double complex y[n]; memset(y, 0, sizeof(y)); fftw_plan p; @@ -139,8 +139,8 @@ void split_op(struct params par, struct operators opr) { sprintf(filename, "output%lu.dat", i); FILE *fp = fopen(filename, "w"); - for (int i = 0; i < opr.size; ++i) { - fprintf(fp, "%d\t%f\t%f\n", i, density[i], creal(opr.v[i])); + for (size_t i = 0; i < opr.size; ++i) { + fprintf(fp, "%ld\t%f\t%f\n", i, density[i], creal(opr.v[i])); } fclose(fp); diff --git a/contents/stable_marriage_problem/code/c/stable_marriage.c b/contents/stable_marriage_problem/code/c/stable_marriage.c index 546a0d5d1..e4f4ad2fd 100644 --- a/contents/stable_marriage_problem/code/c/stable_marriage.c +++ b/contents/stable_marriage_problem/code/c/stable_marriage.c @@ -20,11 +20,11 @@ void shuffle(size_t *array, size_t size) { } } -void create_group(struct person *group, size_t size, bool are_men) { +void create_group(struct person *group, size_t size) { for (size_t i = 0; i < size; ++i) { group[i].id = i; group[i].partner = NULL; - group[i].prefers = (size_t*)malloc(sizeof(size_t) * size); + group[i].prefers = malloc(sizeof(size_t) * size); group[i].index = 0; for (size_t j = 0; j < size; ++j) { @@ -43,6 +43,7 @@ bool prefers_partner(size_t *prefers, size_t partner, size_t id, size_t size) { return false; } } + return true; } void stable_marriage(struct person *men, struct person *women, size_t size) { @@ -85,8 +86,8 @@ int main() { struct person men[5], women[5]; - create_group(men, 5, true); - create_group(women, 5, false); + create_group(men, 5); + create_group(women, 5); for (size_t i = 0; i < 5; ++i) { printf("preferences of man %zu: ", i); From f5af3686c0ac9bbc57ca21f905c42eb56e620899 Mon Sep 17 00:00:00 2001 From: Sammy Plat Date: Mon, 29 Nov 2021 23:38:15 +0100 Subject: [PATCH 087/146] Removed C/C++ warnings only for C++ (#957) --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index bd851cf0a..09c939af3 100644 --- a/SConstruct +++ b/SConstruct @@ -23,7 +23,7 @@ env = Environment(ENV=os.environ, 'Go': go_builder}, tools=['gcc', 'gnulink', 'g++', 'gas', 'gfortran']) -env['CCFLAGS'] = '-Wall -Wextra -Werror' +env['CFLAGS'] = '-Wall -Wextra -Werror' env['CXXFLAGS'] = '-std=c++17' env['ASFLAGS'] = '--64' From 25d03e4711d484f84fce32521a39aa36ab8aacef Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Mon, 29 Nov 2021 16:48:46 -0600 Subject: [PATCH 088/146] Move Code Reviewers from Wiki into the book (#946) * Add code Reviewers chapter * Add code reviews to summary * add code reviews to how to contribute * Update contents/code_reviews/code_reviewers.md Co-authored-by: Dimitri Belopopsky * Update contents/code_reviews/code_reviewers.md Co-authored-by: Dimitri Belopopsky * Update contents/code_reviews/code_reviewers.md Co-authored-by: Dimitri Belopopsky * Update contents/code_reviews/code_reviewers.md Co-authored-by: Dimitri Belopopsky * Apply suggestions from code review Co-authored-by: Dimitri Belopopsky * Update contents/code_reviews/code_reviewers.md Co-authored-by: Sammy Plat * Update contents/code_reviews/code_reviewers.md Co-authored-by: Sammy Plat * Update contents/code_reviews/code_reviewers.md * Update contents/code_reviews/code_reviewers.md * Update contents/code_reviews/code_reviewers.md Co-authored-by: Dimitri Belopopsky Co-authored-by: Sammy Plat --- SUMMARY.md | 1 + contents/code_reviews/code_reviewers.md | 69 +++++++++++++++++++ .../how_to_contribute/how_to_contribute.md | 4 +- 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 contents/code_reviews/code_reviewers.md diff --git a/SUMMARY.md b/SUMMARY.md index e41ba39d4..4d4597b1c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,6 +3,7 @@ * [Algorithm Archive](README.md) * [Introduction](contents/introduction/introduction.md) * [How To Contribute](contents/how_to_contribute/how_to_contribute.md) + * [Code Reviewers](contents/code_reviews/code_reviewers.md) * [Plotting](contents/plotting/plotting.md) * [Domain Coloring](contents/domain_coloring/domain_coloring.md) * [Iterated Function Systems](contents/IFS/IFS.md) diff --git a/contents/code_reviews/code_reviewers.md b/contents/code_reviews/code_reviewers.md new file mode 100644 index 000000000..0061ab996 --- /dev/null +++ b/contents/code_reviews/code_reviewers.md @@ -0,0 +1,69 @@ +# Code Reviewers + +If you are comfortable reviewing a language, please add yourself to the table below: + +[//]: # (To add yourself to the table, please add a link at the bottom of the article and reference yourself in the following format next to each language [@username]. If there are multiple usernames for a language, make sure to seperate them with commas) + +Language | Reviewers +-|- +asm-x64 | +bash | +c | [@amaras] +c# | +clojure | +coconut | [@amaras] +c++ | [@ShadowMitia] +crystal | +D | +dart | +elm | +emojicode | +factor | +fortran | [@leios] +gnuplot | [@leios] +go | +haskell | +java | +javascript | [@ntindle],[@ShadowMitia] +julia | [@leios] +kotlin | +labview | +lolcode | +lisp | +lua | +matlab | +nim | +ocaml | [@ShadowMitia] +php | +piet | +powershell | +python | [@ntindle],[@ShadowMitia],[@amaras],[@PeanutbutterWarrior] +r | +racket | +ruby | +rust | [@ShadowMitia],[@PeanutbutterWarrior] +scala | +scheme | +scratch | [@leios] +smalltask | +swift | +typescript | [@ntindle] +v | +viml | +whitespace | + +If you are comfortable reviewing a toolchain change, please add yourself to the list below: + +Feature | Reviewers +-|- +Dev Container | [@ntindle], [@ShadowMitia] +Docker | [@ntindle], [@ShadowMitia] +Github Actions | [@ntindle] +Honkit | +Scons | [@amaras],[@PeanutbutterWarrior] +Chapters | [@leios] + +[@leios]: https://github.com/leios +[@ntindle]: https://github.com/ntindle +[@amaras]: https://github.com/amaras +[@ShadowMitia]: https://github.com/ShadowMitia diff --git a/contents/how_to_contribute/how_to_contribute.md b/contents/how_to_contribute/how_to_contribute.md index 010bc9a26..abadc5385 100644 --- a/contents/how_to_contribute/how_to_contribute.md +++ b/contents/how_to_contribute/how_to_contribute.md @@ -15,7 +15,9 @@ For now, here are the basics for submitting code to the Algorithm Archive: 3. **CONTRIBUTORS.md**: After contributing code, please echo your name to the end of `CONTRIBUTORS.md` with `echo "- name" >> CONTRIBUTORS.md`. 4. **Building the Algorithm Archive**: Before every submission, you should build the Algorithm Archive on your own machine. To do this, install [Node](https://nodejs.org/) and use `npm install` and then `npm run serve` in the main directory (where `README.md` is). This will provide a local URL to go to to view the archive in your browser of choice. Use this server to make sure your version of the Algorithm Archive works cleanly for the chapter you are updating! -To submit code, simply go to the `code/` directory of whatever chapter you want and add another directory for your language of choice. +To **submit code**, go to the `code/` directory of whatever chapter you want and add another directory for your language of choice. + +You can also help out by **reviewing code**, if you have the ability to review a language (and want to be asked to do so), please add yourself to [the Code Reviewers list](../code_reviews/code_reviewers.md) We use two GitBook plugins to allow users to flip between languages on different algorithms. One is the theme-api, and the other is the include-codeblock api. From 714f2c8827a4608637cfb614d1ff3e9f0e6fa57b Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Mon, 29 Nov 2021 16:53:43 -0600 Subject: [PATCH 089/146] Speed up container start times by pulling prebuilt the image from GitHub (#942) * feat: pull the image from GHCR to speed up start of the container * code review changes * fix: spelling error and clarification Co-authored-by: Dimitri Belopopsky --- .devcontainer/devcontainer.json | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e9d6bbefa..352dcca68 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,26 +1,24 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/ubuntu +// For format details, see https://aka.ms/devcontainer.json. { - "name": "Ubuntu", - "build": { - "dockerfile": "../Dockerfile", - // Update 'VARIANT' to pick an Ubuntu version: focal, bionic - "args": { "VARIANT": "focal" } - }, + "name": "Arcane Algorithm Archive All Languages", + + // Comment out 'image' and uncomment 'build' to test changes to the dockerfile locally + "image": "ghcr.io/algorithm-archivists/aaa-langs:latest", + // "build": {\ + // // For config options, see the README at:https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/ubuntu + // "dockerfile": "../Dockerfile", + // // Update 'VARIANT' to pick an Ubuntu version: focal, bionic + // "args": { "VARIANT": "focal" } + // }, // Set *default* container specific settings.json values on container create. "settings": {}, - // Add the IDs of extensions you want installed when the container is created. "extensions": [], - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", - - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode" + // Use 'forwardPorts' to make a list of ports inside the container available locally (outside the container). + // Port : Usage + // 4000 : Honkit serves by default on this port + "forwardPorts": [4000] } From 9193bf73b2c44cee22ea6c46920a6a89f06b2d9d Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 29 Nov 2021 23:57:05 +0100 Subject: [PATCH 090/146] Update code_reviewers.md (#958) --- contents/code_reviews/code_reviewers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/contents/code_reviews/code_reviewers.md b/contents/code_reviews/code_reviewers.md index 0061ab996..e2fd22b0a 100644 --- a/contents/code_reviews/code_reviewers.md +++ b/contents/code_reviews/code_reviewers.md @@ -67,3 +67,4 @@ Chapters | [@leios] [@ntindle]: https://github.com/ntindle [@amaras]: https://github.com/amaras [@ShadowMitia]: https://github.com/ShadowMitia +[@PeanutbutterWarrior]: https://github.com/PeanutbutterWarrior From 5116769557bc415f78199f3c48673df94c25a6c0 Mon Sep 17 00:00:00 2001 From: stormofice <58337328+stormofice@users.noreply.github.com> Date: Tue, 30 Nov 2021 05:00:31 +0100 Subject: [PATCH 091/146] Changed action to only run in main repository (#955) Co-authored-by: Nicholas Tindle --- .github/workflows/publish_container.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/publish_container.yml b/.github/workflows/publish_container.yml index 84759dbdf..68268afa4 100644 --- a/.github/workflows/publish_container.yml +++ b/.github/workflows/publish_container.yml @@ -6,6 +6,7 @@ on: jobs: build: runs-on: ubuntu-latest + if: github.repository == 'algorithm-archivists/algorithm-archive' steps: - uses: actions/checkout@master - name: Publish to Registry From 93d4a178e279169a0c79feeb2f2166a986b66237 Mon Sep 17 00:00:00 2001 From: James Schloss Date: Tue, 30 Nov 2021 16:30:27 +0100 Subject: [PATCH 092/146] master -> main (#953) * updating all masters to main Co-authored-by: Dimitri Belopopsky Co-authored-by: Dimitri Belopopsky --- .github/workflows/deploy.yml | 2 +- .github/workflows/publish_container.yml | 4 +- .gitignore | 3 + .travis.yml | 29 -- contents/IFS/IFS.md | 2 +- .../affine_transformations.md | 2 +- .../approximate_counting.md | 2 +- .../backward_euler_method.md | 2 +- .../barnes_hut_algorithm.md | 2 +- contents/barnsley/barnsley.md | 2 +- contents/bitlogic/bitlogic.md | 2 +- contents/cc/license.txt | 2 +- contents/chans_algorithm/chans_algorithm.md | 2 +- .../choosing_a_language.md | 2 +- .../compiled_languages/compiled_languages.md | 2 +- .../computational_geometry.md | 2 +- contents/computus/computus.md | 2 +- contents/convolutions/1d/1d.md | 2 +- contents/convolutions/2d/2d.md | 2 +- .../convolutional_theorem.md | 2 +- contents/cooley_tukey/cooley_tukey.md | 2 +- contents/data_compression/data_compression.md | 2 +- contents/data_structures/data_structures.md | 2 +- .../decision_problems/decision_problems.md | 2 +- .../differential_equations.md | 2 +- contents/domain_coloring/domain_coloring.md | 2 +- .../domain_coloring/domain_coloring.md.bak | 185 ------------- .../euclidean_algorithm.md | 2 +- contents/flood_fill/flood_fill.md | 2 +- contents/flood_fill/flood_fill.md.bak | 258 ------------------ contents/fortran/fortran.md | 2 +- .../forward_euler_method.md | 2 +- .../gaussian_elimination.md | 2 +- contents/gift_wrapping/gift_wrapping.md | 2 +- contents/graham_scan/graham_scan.md | 2 +- .../how_to_contribute/how_to_contribute.md | 2 +- contents/huffman_encoding/huffman_encoding.md | 2 +- contents/introduction/introduction.md | 2 +- contents/jarvis_march/jarvis_march.md | 2 +- contents/makefiles/makefiles.md | 2 +- .../mathematical_background.md | 2 +- contents/matrix_methods/matrix_methods.md | 2 +- .../monte_carlo_integration.md | 2 +- contents/multiplication/multiplication.md | 2 +- .../my_introduction_to_hobby_programming.md | 2 +- contents/notation/notation.md | 2 +- contents/physics_solvers/physics_solvers.md | 2 +- contents/plotting/plotting.md | 2 +- .../quantum_information.md | 2 +- contents/quantum_systems/quantum_systems.md | 2 +- .../split-operator_method.md | 2 +- .../stable_marriage_problem.md | 2 +- .../stacks_and_queues/stacks_and_queues.md | 2 +- .../taylor_series_expansion.md | 2 +- contents/thomas_algorithm/thomas_algorithm.md | 2 +- contents/tree_traversal/tree_traversal.md | 2 +- .../verlet_integration/verlet_integration.md | 2 +- update_site.sh | 44 --- 58 files changed, 57 insertions(+), 570 deletions(-) delete mode 100644 .travis.yml delete mode 100644 contents/domain_coloring/domain_coloring.md.bak delete mode 100644 contents/flood_fill/flood_fill.md.bak delete mode 100755 update_site.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 361978a7a..e07b1fade 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Build and Deploy on: push: branches: - - master + - main jobs: build-and-deploy: diff --git a/.github/workflows/publish_container.yml b/.github/workflows/publish_container.yml index 68268afa4..d1edec703 100644 --- a/.github/workflows/publish_container.yml +++ b/.github/workflows/publish_container.yml @@ -2,7 +2,7 @@ name: Publish Docker on: push: branches: - - master + - main jobs: build: runs-on: ubuntu-latest @@ -15,4 +15,4 @@ jobs: name: algorithm-archivists/aaa-langs username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - registry: ghcr.io \ No newline at end of file + registry: ghcr.io diff --git a/.gitignore b/.gitignore index 4d5a431b0..09a7ab178 100644 --- a/.gitignore +++ b/.gitignore @@ -528,3 +528,6 @@ build/ # Cargo artifacts Cargo.lock target/ + +*.out +*.class diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b497e39e2..000000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -dist: trusty -sudo: false - -language: node_js -node_js: - - "12" - -before_script: - - export BOOK_BUILD_DIR="${TRAVIS_BUILD_DIR}"/_book - - env | sort - -script: - - npm run build - # Make sure the book built. - - | - book_check_file="${BOOK_BUILD_DIR}/index.html" - if [[ ! -f "${book_check_file}" ]]; then - echo "${book_check_file} not found" - exit 1 - fi - -after_success: - - | - if [[ "${TRAVIS_BRANCH}" == master && "${TRAVIS_PULL_REQUEST}" == false ]]; then - # Commits to master that are not pull requests, that is, only - # actual addition of code to master, should deploy the book to - # the site. - bash "${TRAVIS_BUILD_DIR}"/tools/deploy/update_site_travis.bash - fi diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index 9431e4631..cd503ae46 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -246,7 +246,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/affine_transformations/affine_transformations.md b/contents/affine_transformations/affine_transformations.md index 88f140443..439440b80 100644 --- a/contents/affine_transformations/affine_transformations.md +++ b/contents/affine_transformations/affine_transformations.md @@ -308,7 +308,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/approximate_counting/approximate_counting.md b/contents/approximate_counting/approximate_counting.md index ae4a765d6..5e06e43b5 100644 --- a/contents/approximate_counting/approximate_counting.md +++ b/contents/approximate_counting/approximate_counting.md @@ -380,7 +380,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/backward_euler_method/backward_euler_method.md b/contents/backward_euler_method/backward_euler_method.md index ba3d72ba2..090ffb191 100644 --- a/contents/backward_euler_method/backward_euler_method.md +++ b/contents/backward_euler_method/backward_euler_method.md @@ -13,7 +13,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/barnes_hut_algorithm/barnes_hut_algorithm.md b/contents/barnes_hut_algorithm/barnes_hut_algorithm.md index f4d4301b5..83c6f6003 100644 --- a/contents/barnes_hut_algorithm/barnes_hut_algorithm.md +++ b/contents/barnes_hut_algorithm/barnes_hut_algorithm.md @@ -16,7 +16,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index 9c353f8b4..6b2d6b3bf 100644 --- a/contents/barnsley/barnsley.md +++ b/contents/barnsley/barnsley.md @@ -151,7 +151,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/bitlogic/bitlogic.md b/contents/bitlogic/bitlogic.md index 077bf278c..c6b1dd9fd 100644 --- a/contents/bitlogic/bitlogic.md +++ b/contents/bitlogic/bitlogic.md @@ -148,7 +148,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/cc/license.txt b/contents/cc/license.txt index e9c662f91..1e11bba93 100644 --- a/contents/cc/license.txt +++ b/contents/cc/license.txt @@ -3,7 +3,7 @@ ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/chans_algorithm/chans_algorithm.md b/contents/chans_algorithm/chans_algorithm.md index 62e125114..18daaa889 100644 --- a/contents/chans_algorithm/chans_algorithm.md +++ b/contents/chans_algorithm/chans_algorithm.md @@ -10,7 +10,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/choosing_a_language/choosing_a_language.md b/contents/choosing_a_language/choosing_a_language.md index 88ad8c986..5385c309a 100644 --- a/contents/choosing_a_language/choosing_a_language.md +++ b/contents/choosing_a_language/choosing_a_language.md @@ -73,7 +73,7 @@ Please let me know which languages you want to cover and I'll add them here! ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/compiled_languages/compiled_languages.md b/contents/compiled_languages/compiled_languages.md index 3f6424359..b8bac2e75 100644 --- a/contents/compiled_languages/compiled_languages.md +++ b/contents/compiled_languages/compiled_languages.md @@ -35,7 +35,7 @@ I just find it easier to avoid GUI's whenever possible. ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/computational_geometry/computational_geometry.md b/contents/computational_geometry/computational_geometry.md index a99c0a4e9..bcd702fd7 100644 --- a/contents/computational_geometry/computational_geometry.md +++ b/contents/computational_geometry/computational_geometry.md @@ -12,7 +12,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/computus/computus.md b/contents/computus/computus.md index 3a881cdb0..c3ec51f09 100644 --- a/contents/computus/computus.md +++ b/contents/computus/computus.md @@ -343,7 +343,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/convolutions/1d/1d.md b/contents/convolutions/1d/1d.md index 9a2e652d1..ecf56a1df 100644 --- a/contents/convolutions/1d/1d.md +++ b/contents/convolutions/1d/1d.md @@ -304,7 +304,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Images/Graphics - The image "[Square Wave](../res/square_wave.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). diff --git a/contents/convolutions/2d/2d.md b/contents/convolutions/2d/2d.md index dc52157fe..e2cace847 100644 --- a/contents/convolutions/2d/2d.md +++ b/contents/convolutions/2d/2d.md @@ -170,7 +170,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Images/Graphics - The image "[8bit Heart](../res/heart_8bit.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). diff --git a/contents/convolutions/convolutional_theorem/convolutional_theorem.md b/contents/convolutions/convolutional_theorem/convolutional_theorem.md index 1034f2018..b47bec179 100644 --- a/contents/convolutions/convolutional_theorem/convolutional_theorem.md +++ b/contents/convolutions/convolutional_theorem/convolutional_theorem.md @@ -62,7 +62,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Images/Graphics diff --git a/contents/cooley_tukey/cooley_tukey.md b/contents/cooley_tukey/cooley_tukey.md index b30052e40..d528832d1 100644 --- a/contents/cooley_tukey/cooley_tukey.md +++ b/contents/cooley_tukey/cooley_tukey.md @@ -265,7 +265,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/data_compression/data_compression.md b/contents/data_compression/data_compression.md index 1f48c0c99..5a04c3706 100644 --- a/contents/data_compression/data_compression.md +++ b/contents/data_compression/data_compression.md @@ -130,7 +130,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/data_structures/data_structures.md b/contents/data_structures/data_structures.md index 11ae7aa4b..60680b95e 100644 --- a/contents/data_structures/data_structures.md +++ b/contents/data_structures/data_structures.md @@ -7,7 +7,7 @@ The fundamental building blocks of algorithms are data structures, and thus as m ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/decision_problems/decision_problems.md b/contents/decision_problems/decision_problems.md index 064c1d067..2ab9ed612 100644 --- a/contents/decision_problems/decision_problems.md +++ b/contents/decision_problems/decision_problems.md @@ -14,7 +14,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/differential_equations/differential_equations.md b/contents/differential_equations/differential_equations.md index 3cfbba1fa..0bb08349c 100644 --- a/contents/differential_equations/differential_equations.md +++ b/contents/differential_equations/differential_equations.md @@ -7,7 +7,7 @@ Here, we discuss many different methods to solve particular sets of differential ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/domain_coloring/domain_coloring.md b/contents/domain_coloring/domain_coloring.md index 39159e650..9c536bb50 100644 --- a/contents/domain_coloring/domain_coloring.md +++ b/contents/domain_coloring/domain_coloring.md @@ -190,7 +190,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/domain_coloring/domain_coloring.md.bak b/contents/domain_coloring/domain_coloring.md.bak deleted file mode 100644 index 8ec9129ad..000000000 --- a/contents/domain_coloring/domain_coloring.md.bak +++ /dev/null @@ -1,185 +0,0 @@ -# Domain coloring - -Domain coloring is a much more complicated plotting technique than those outlined in the [plotting chapter](../plotting/plotting.md) and is used to plot complex functions where both the input and output have imaginary and real components. -For the code in this chapter, we will focus on languages that are easily able to plot two-dimensional images or heatmaps, instead of languages meant for number-crunching. -That is to say that this chapter will certainly have a code implementation in gnuplot, but it will not likely have an implementation in C, Fortran, or Java because these languages do not have plotting capabilities in-built. - -Imagine the following function: $$f(z) = z^2$$. -In this case, we could create a plot that looks like this: - -

- -

- -This indicates that for various input values along $$z$$, we have different function outputs from $$f(z)$$. -Now let's imagine another function with complex input $$(z \in \mathbb{C})$$, but a purely real output $$(f(z) \in \mathbb{R})$$: - -$$ -f(z) = |z| -$$ - -In this case, each complex input has a real output. -This can be plotted as a two-dimensional dataset like so: - -

- -

- -Here, the $$x$$-axis and $$y$$-axis represent the real and imaginary components of the input variable, respectively. -The colorbar represents the output of $$f(z)$$. - -At this point, we can start to see the problem. -If the output of $$f(z)$$ also requires plotting of the real and imaginary components, then we would need four dimensions to appropriately represent the function space, one axis for the real component and another for the imaginary component of both the input ($$z$$) and the output of $$f(z)$$! -Unfortunately, feeble human minds are incapable of understanding four spatial dimensions without projecting onto lower dimensionality, so we need to improvise. - -We do this by assuming the complex output can be represented in the following form: - -$$ -z = re^{i \theta} = r(\cos(\theta) + i\sin(\theta)) -$$ - -where, $$r$$ is a complex magnitude and $$\theta$$ is a complex phase. -This is the formula for a circle in the complex plane and we can easily find $$r$$ and $$\theta$$ like so: - -$$ -\begin{align} - r &= \sqrt{\text{Re}(z)^2 + \text{Im}(z)^2} \\ - \theta &= \text{atan}\left(\frac{\text{Im}(z)}{\text{Re}(z)}\right) -\end{align} -$$ - -Once we have our complex function output in this form, we then color the output domain according to a color space with at least 2 independent dimensions, like RGB (Red, Green, Blue), or HSV (Hue, Saturation, Value) [CITE]. -The choice of color space is completely dependent on what the users feel is most visually intuitive. -In any case, one dimension of the color system will be used to represent the complex magnitude of the output and another dimension of the color system will be used to represent the complex phase. -The $$xy$$ grid will be representing the real and imaginary inputs to these functions. -That is to say, we plug every value in the 2D complex plane into the function and then color each pixel based on the function output. - -As an example, let's look at the simplest function we can $$f(z) = z$$, but in this case $$z \in \mathbb{C}$$. -If we use an RGB color scheme, where red represents $$\theta$$ and blue represents $$r$$, we can generate the following image: - -

- -

- -As a note here, there is a clear phase discontinuity along the vertical axis. -That is to say that the complex phase wraps around the origin, ranging from 0 (clear) to $$2\pi$$ (red). -In addition, the edges of the plot are blue because the function value increases linearly as we move from the origin. - -If we instead look at the function $$f(z) = z^2$$, we can generate a similar plot: - -

- -

- -Here, it is clear that the complex phase wraps around the origin twice, creating two separate phase discontinuities on top of each other. -This indicates a $$4\pi$$ phase winding, and for some purposes, such as vortex tracking for inviscid fluids, this visualizaton is ideal, because a vortex is located precisely at the phase discontinuity [CITE]. -For other purposes, the discontinuity is visually distracting, and for this reason, many people use an HSV scheme for plotting complex functions. -So here is the same function $$\left(f(z)=z^2\right)$$, but using hue to represent the complex phase and saturation to represent the magnitude. - -

- -

- -Here, the value for HSV was always set to 1. -When looking at the edges of the plot, the hue changes rapidly, but each color is mirrored on the oposite edge. -This indicates the $$4\pi$$ phase winding we saw in the RGB plots. -Also, because the complex magnitude increases as we move further from the center of the plot, the saturation also increases. -Thus the very center of the plot is completely washed out! -We need to fix this in subsequent plots to make them representative of the actual data. - -One easy way to show that the complex magnitude is increasing as we move further from the origin is with contours. -Essentially, at ever integer value of the magnitude, we want to draw some kind of line. -There are a number of ways to generate these lines, and one simple way is by using an alternative shading function like so: - -$$ -g(r) = r-\lfloor r \rfloor. -$$ - -This will create the following image: - -

- -

- -This function will essentially create a smooth gradient, but because of the floor operation $$\left(\lfloor \cdot \rfloor \right)$$, the saturation will go from 0 to 1 between each integer value of the magnitude. -Here, it is clear that the magnitude is increasing as $$z^2$$ from the origin; however, because the saturation is fluctuating so much, it is difficult to see the phase pattern next to each contour. -This can be fixed simply by adding an offset to the shading function such that, - -$$ -g(r) = \frac{1}{2} + \frac{1}{2}\left(r-\lfloor r \rfloor \right). -$$ - -Which will produce the following image: - -

- -

- -This means that the saturation will fluctuate from $$\frac12$$ to 1 instead of from 0 to 1, which makes it way easier to see phase information next to contours. -Again, there is a lot of ways to play with these equations, so feel free to use whatever function you want! -As long as some sort of rounding operation is used to establish some form of integer value for the magnitude, it should be possible to create contours of various types. - -Unfortunately, there the changing saturation only shows changes in the complex magnitude, and changing hue only shows changes in the complex phase. -Neither the magnitude or the phase directly show what is happening in real or imaginary space with the output. -To show this, we might want to draw gridlines that color out grid black whenever the imaginary or real components of the output function are integer values. - -For example, let's go back to a simpler function $$f(z) = z$$. -If we draw lines on this plot, corresponding to integer values in the output, we get a simple grid - -

- -

- -Like before, the choice of which function to use in order to create the gridlines is somewhat arbitrary. -It is important to choose a function that sharply drops to 0 or peaks at 1 for all integer values, and then you multiply this by the output of $$f(z)$$. -For these purposes, we chose the following function - -$$ -h(z) = |\sin(\pi\times\text{Re}(f(z)))^t|\times|\sin(\pi\times\text{Im}(f(z)))^t|, -$$ - -where $$t$$ is some threshold value, and was set to be 0.1 in our plot. -A plot of h(z) for $$f(z) = z$$ where $$z\in\mathbb{R}$$ is shown below: - -

- -

- -So, putting it altogether and returning to the function of $$f(z) = z^2$$, we find the following image. - -

- -

- -Here, the diagonal lines through the center represent integer values along the imaginary axis for $$f(z)$$ and the vertical and horizontal represent integer values of the real axis for $$f(z)$$. - -## Example Code - -Here is the full script to generate a domain colored output of $$f(z)=z^2$$. - -### Bibliography - -{% references %} {% endreferences %} - - - -## License - -##### Code Examples - -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). - -##### Text - -The text of this chapter was written by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). - -[

](https://creativecommons.org/licenses/by-sa/4.0/) - -##### Images/Graphics - -##### Pull Requests - -The following pull requests have modified the text or graphics of this chapter: -- none diff --git a/contents/euclidean_algorithm/euclidean_algorithm.md b/contents/euclidean_algorithm/euclidean_algorithm.md index 1d6211a37..cebf550ba 100644 --- a/contents/euclidean_algorithm/euclidean_algorithm.md +++ b/contents/euclidean_algorithm/euclidean_algorithm.md @@ -302,7 +302,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/flood_fill/flood_fill.md b/contents/flood_fill/flood_fill.md index 4c7e5936e..62348f107 100644 --- a/contents/flood_fill/flood_fill.md +++ b/contents/flood_fill/flood_fill.md @@ -279,7 +279,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/flood_fill/flood_fill.md.bak b/contents/flood_fill/flood_fill.md.bak deleted file mode 100644 index d15b1ef97..000000000 --- a/contents/flood_fill/flood_fill.md.bak +++ /dev/null @@ -1,258 +0,0 @@ -# Flood Fill - -Flood fill is a method that is surprisingly useful in a large number of different situations and keeps finding me wherever I go. -When I was completing my PhD, I had an idea to track superfluid vortices by using flood fill as a way to help mask out unnecessary features of the simulation. -When I was making a terminal game, I thought of creating an animation that was just flood fill in disguise. -When I decided to play minesweeper or Go with my girlfriend, flood fill was used in both! - -Flood fill is probably most commonly known as the "Bucket Fill" application in most art programs {{ "gimp_bucket" | cite }}. -It's usually indicated by an icon that looks like a bucket and is known to fill in any enclosed area, as shown below: - -

- -

- -Because flood fill is incredibly common, there are a large number of variations to the method, some of which are more optimal than others. -For this chapter, we will cover the basics: how to fill a domain in a quick and dirty way. -In subsequent chapters, we will continue our journey by creating more and more efficient flood fill methods, including scanline-based and fixed memory methods {{ "torbert2016" | cite }}. - -I have decided to split the chapter up for a few important reasons: -1. I did not want to flood the Algorithm Archive with flood fill methods all at the same time. -I feel it's worth letting each chapter sit for a bit while we savour it's unique flavour. -2. Many users are implementing versions of each algorithm in their own languages and it is difficult to review and submit code for chapters with a lot of code chunks. -Several sub-chapters with less code is easier for everyone. -3. I am kinda under a time-constraint right now and wanted to make sure we regularly get content into the Algorithm Archive. - -So, without further a-do, let's hop right into it! - - -## What does flood fill do? - -Flood fill is essentially composed of 2 parts: -1. Determining the extents of the domain to fill -2. Walking through all elements within a domain and changing some property - -For the purposes of this chapter, we will be using a set of floating-point values that range from 0 to 1 instead of a color-space like RGB. -Though bucket fill is always used in art programs in some sort of color space, flood fill is more general and can be used in a space with any type of element. -As such, it makes sense to use a simpler element type so we can better understand the method. - -So how do we go about finding the extents of the domain to fill? - -Here, a domain will be defined as any connected set of elements in an $$n$$-dimensional space whose values do not vary beyond a pre-defined threshold. -As an example, if we take a circle embedded into a 2-dimensional grid, we have 3 separate domains: -1. Inside the circle where all elements are 0. -2. The circle, itself, where the elements are set to 0.75. -3. Outside the circle where all elements are similarly 0. - -

- -

- -Though there are some more complicated ways to determine the extents of the domain, we will not focus on this aspect of the flood fill method for the remainder of this chapter and instead leave it for subsequent chapters. -So now we will focus on the process of walking through each element in the domain and changing some property. - -## Domain traversal - -As before, the simplest example to work with is that of an image, where each element in our domain is a single pixel. -Here, we can connect each pixel to all other pixels in its vicinity, like so: - -

- -

- -In this image, a border is shown between each individual pixel and a grid is superimposed to show how each pixel is connected to its neighbors. -This means that each element has 4 neighbors: north, south, east, and west. -We could also include northeast, southeast, southwest, and northwest if we wanted to do an 8-way fill, but we will restrict the discussion to the 4-way fill for now, as the method is essentially the same and slightly easier to understand with fewer elements to worry about. - -By connecting each pixel to its neighbors in this way, the flood fill operation becomes a process of graph traversal, not too dissimilar from the [tree traversal](../tree_traversal/tree_traversal.md) methods described before. -This means that after selecting our initial location, we can then traverse through all elements in either a depth-first or breadth-first fashion. -We will be covering the following this chapter: - -1. Finding all neighbours -2. Depth-first node traversal -3. Breadth-first node traversal and small-scale optimizations - -So let's start by discussing how we might go about finding the neighbors to fill. - -### Finding all neighbors - -The first step of this method is to query the location of all possible neighbors. -At first glance, this seems rather straightforward. -One simply needs to look up, down, left, and right of the current location and add those elements to the list of neighbors if they are: - -1. On the canvas -2. Have a value *close enough* to the old value we would like to replace - -In code, this might look like this: - -{% method %} -{% sample lang="jl" %} -[import:37-55, lang:"julia"](code/julia/flood_fill.jl) -{% endmethod %} - - -This code is set up to return a vector of elements to then use for subsequent sections. - -### Depth-first node traversal - -Now that we have the ability to find all neighboring elements, we can proceed to traverse through those nodes in the most straightforward way: recursion. - -In code, it might look like this: - -{% method %} -{% sample lang="jl" %} -[import:106-118, lang:"julia"](code/julia/flood_fill.jl) - -All Julia code snippets for this chapter rely on an exterior `color!(...)` function, defined as - -[import:23-35, lang:"julia"](code/julia/flood_fill.jl) -{% endmethod %} - -The above code continues recursing through available neighbors as long as neighbors exist, and this should work so long as we are adding the correct set of neighbors. - -Additionally, it is possible to do the same type of traversal by managing a stack, like so: - -{% method %} -{% sample lang="jl" %} -[import:57-77, lang:"julia"](code/julia/flood_fill.jl) -{% endmethod %} - -This is ultimately the same method of traversal as before; however, because we are managing our own data structure, there are a few distinct differences: -1. The manually managed stack could be slightly slower and potentially more memory-intensive -2. It is easy to reach the maximum recursion depth on certain hardware with the recursive method, so it is best to use the stack-based implementation in those cases. - -If we were to use either of these methods to fill a circle embedded in a two dimensional domain, we would see the following - -
- -
- -Here, we see that these methods will traverse through one direction first before filling from there. -This is potentially the easiest method to write, but it is not the most intuitive fill pattern. -I suspect that if someone was asked to fill the contents of the circle on their own, they would fill it more evenly from the center, like so: - -
- -
- -This is simply another traversal strategy known as breadth-first traversal and comes with its own set of caveats. -We will discuss this further in the next subsection - -### Breadth-first node traversal and small-scale optimizations - -Breadth-first node traversal is as simple as switching the stack in the depth-first strategy with a queue. -The code would look something like this: - -{% method %} -{% sample lang="jl" %} -[import:80-104, lang:"julia"](code/julia/flood_fill.jl) -{% endmethod %} - -Now, there is a small trick in this code that must be considered to make sure it runs optimally. -Namely, the nodes must be colored *when they are being enqueued*, not when visiting the node. -At least for me, it was not immediately obvious why this would be the case, but let me try to explain. - -Let's imagine that we decided to write code that colored all neighboring nodes only when visiting them. -When querying all possible neighbors, we will add 4 elements to the queue for the north, south, east, and west neighbors of the initial node, as shown below: - -

- -

- -Now let's imagine we travel east first. -It then enqueues three more nodes: north, south, and east again. -This is shown below: - -

- -

- -It does not enqueue its west neighbour because this has already been colored. -At this stage, we will have six nodes ready to be colored and 2 that are already colored. -Now let's say we travel north next. -This node will enqueue three more nodes: west, north, and east, as shown below: - -

- -

- -The problem is that the east element has *already been enqueued for coloring by the previous node*!. -This shared element is colored in red. -As we progress through all four initial neighbours, we will find 4 nodes that are doubly enqueued: all directions diagonal to the initial location! -This is again shown below: - -

- -

- -As the number of nodes increases, so does the number of duplicate nodes. -A quick fix is to color the nodes *when they are being enqueud* like in the example code above. -When doing this, duplicates will not be enqueued with a breadth-first scheme because they will already be colored when other nodes are trying to find their neighbors. -This created a node connection pattern like so: - -

- -

- -As some final food for thought: why wasn't this a problem with the depth-first strategy? -The simple answer is that it actually was an issue, but it was way less prevalent. -With the depth-first strategy, a number of unnecessary nodes are still pushed to the stack, but because we consistently push one direction before spreading out to other directions, it is more likely that the nodes have filled neighbours when they are looking for what to fill around them. - -Simply put: depth-first traversal is slightly more efficient in this case unless you can color as querying for neighbors, in which case breadth-first is more efficient. - -## Conclusions - -As stated before, the method discussed in this chapter is just the tip of the iceberg and many other flood fill methods exist that are likely to be more efficient for most purposes. -These will all be covered in subsequent chapters which will come out somewhat regularly throughout the next few months, lest we flood that archive with flood fill methods. - -## Example Code - -The example code for this chapter will be the simplest application of flood fill that still adequately tests the code to ensure it is stopping at boundaries appropriately. -For this, we will create a two dimensional array of floats, all starting at 0.0, and then set a single vertical line of elements at the center to be 1.0. -After, we will fill in the left-hand side of the array to be all ones by choosing any point within the left domain to fill. - -{% method %} -{% sample lang="jl" %} -[import, lang:"julia"](code/julia/flood_fill.jl) -{% endmethod %} - - -### Bibliography - -{% references %} {% endreferences %} - - - -## License - -##### Code Examples - -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). - -##### Text - -The text of this chapter was written by [James Schloss](https://github.com/leio) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). - -[

](https://creativecommons.org/licenses/by-sa/4.0/) - -##### Images/Graphics -- The image "[Example Bucket Fill](res/example.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Circle Domains](res/simple_circle.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 1](res/grid_1.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 2](res/grid_2.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 3](res/grid_3.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 4](res/grid_4.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 5](res/grid_5.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The image "[Grid 6](res/grid_6.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The video "[Stack Fill](res/recurse_animation.mp4)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). -- The video "[Queue Fill](res/queue_animation.mp4)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). - - diff --git a/contents/fortran/fortran.md b/contents/fortran/fortran.md index f705d3c17..491a33b6e 100644 --- a/contents/fortran/fortran.md +++ b/contents/fortran/fortran.md @@ -6,7 +6,7 @@ Alright, so here's the thing about Fortran. It's old. ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/forward_euler_method/forward_euler_method.md b/contents/forward_euler_method/forward_euler_method.md index f97ff27a2..dfb185431 100644 --- a/contents/forward_euler_method/forward_euler_method.md +++ b/contents/forward_euler_method/forward_euler_method.md @@ -156,7 +156,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/gaussian_elimination/gaussian_elimination.md b/contents/gaussian_elimination/gaussian_elimination.md index 8caf869ed..4eaf61570 100644 --- a/contents/gaussian_elimination/gaussian_elimination.md +++ b/contents/gaussian_elimination/gaussian_elimination.md @@ -591,7 +591,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/gift_wrapping/gift_wrapping.md b/contents/gift_wrapping/gift_wrapping.md index 176463672..59bbc4d91 100644 --- a/contents/gift_wrapping/gift_wrapping.md +++ b/contents/gift_wrapping/gift_wrapping.md @@ -14,7 +14,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/graham_scan/graham_scan.md b/contents/graham_scan/graham_scan.md index 7b84f3acd..7b46422cb 100644 --- a/contents/graham_scan/graham_scan.md +++ b/contents/graham_scan/graham_scan.md @@ -105,7 +105,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/how_to_contribute/how_to_contribute.md b/contents/how_to_contribute/how_to_contribute.md index abadc5385..b8aa1d624 100644 --- a/contents/how_to_contribute/how_to_contribute.md +++ b/contents/how_to_contribute/how_to_contribute.md @@ -38,7 +38,7 @@ Thanks for all the support and considering contributing to the Algorithm Archive ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/huffman_encoding/huffman_encoding.md b/contents/huffman_encoding/huffman_encoding.md index 3772c97ca..881c4c47c 100644 --- a/contents/huffman_encoding/huffman_encoding.md +++ b/contents/huffman_encoding/huffman_encoding.md @@ -110,7 +110,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/introduction/introduction.md b/contents/introduction/introduction.md index dccd6e82a..b9efc5c75 100644 --- a/contents/introduction/introduction.md +++ b/contents/introduction/introduction.md @@ -22,7 +22,7 @@ So I guess that's all for now. Because this book is freely available online, I m ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/jarvis_march/jarvis_march.md b/contents/jarvis_march/jarvis_march.md index 20929d4ad..7fee2e681 100644 --- a/contents/jarvis_march/jarvis_march.md +++ b/contents/jarvis_march/jarvis_march.md @@ -62,7 +62,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/makefiles/makefiles.md b/contents/makefiles/makefiles.md index 3e23c926d..642065257 100644 --- a/contents/makefiles/makefiles.md +++ b/contents/makefiles/makefiles.md @@ -6,7 +6,7 @@ COMING SOON! ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/mathematical_background/mathematical_background.md b/contents/mathematical_background/mathematical_background.md index 4ed9afb45..fa0f36839 100644 --- a/contents/mathematical_background/mathematical_background.md +++ b/contents/mathematical_background/mathematical_background.md @@ -16,7 +16,7 @@ In those cases, we will place the mathematical methods in more relevant sections ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/matrix_methods/matrix_methods.md b/contents/matrix_methods/matrix_methods.md index 96ae1c8b7..89f3f8e3b 100644 --- a/contents/matrix_methods/matrix_methods.md +++ b/contents/matrix_methods/matrix_methods.md @@ -17,7 +17,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/monte_carlo_integration/monte_carlo_integration.md b/contents/monte_carlo_integration/monte_carlo_integration.md index 964de7bbe..c01a6cbbd 100644 --- a/contents/monte_carlo_integration/monte_carlo_integration.md +++ b/contents/monte_carlo_integration/monte_carlo_integration.md @@ -220,7 +220,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/multiplication/multiplication.md b/contents/multiplication/multiplication.md index ea430dee2..75ce2e9cb 100644 --- a/contents/multiplication/multiplication.md +++ b/contents/multiplication/multiplication.md @@ -25,7 +25,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/my_introduction_to_hobby_programming/my_introduction_to_hobby_programming.md b/contents/my_introduction_to_hobby_programming/my_introduction_to_hobby_programming.md index 98ad6607d..eb3260ce9 100644 --- a/contents/my_introduction_to_hobby_programming/my_introduction_to_hobby_programming.md +++ b/contents/my_introduction_to_hobby_programming/my_introduction_to_hobby_programming.md @@ -72,7 +72,7 @@ Basically, since the first time I was able to directly interact with my computer ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/notation/notation.md b/contents/notation/notation.md index 793698d0b..f8242ddde 100644 --- a/contents/notation/notation.md +++ b/contents/notation/notation.md @@ -208,7 +208,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/physics_solvers/physics_solvers.md b/contents/physics_solvers/physics_solvers.md index 6192b4681..12d24c366 100644 --- a/contents/physics_solvers/physics_solvers.md +++ b/contents/physics_solvers/physics_solvers.md @@ -12,7 +12,7 @@ For example, there are many different ways to solve the Schrödinger equation, h ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/plotting/plotting.md b/contents/plotting/plotting.md index 2ad1ae63f..0fd858f6b 100644 --- a/contents/plotting/plotting.md +++ b/contents/plotting/plotting.md @@ -574,7 +574,7 @@ Here, we have provided all of the essential skills to plot any data that comes f ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/quantum_information/quantum_information.md b/contents/quantum_information/quantum_information.md index 56636b724..7916d36b7 100644 --- a/contents/quantum_information/quantum_information.md +++ b/contents/quantum_information/quantum_information.md @@ -33,7 +33,7 @@ As always, this section will be updated as we add more algorithms to the list. ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/quantum_systems/quantum_systems.md b/contents/quantum_systems/quantum_systems.md index c602aaea1..71eb9305a 100644 --- a/contents/quantum_systems/quantum_systems.md +++ b/contents/quantum_systems/quantum_systems.md @@ -260,7 +260,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/split-operator_method/split-operator_method.md b/contents/split-operator_method/split-operator_method.md index ad4fd6c0e..1af23e331 100644 --- a/contents/split-operator_method/split-operator_method.md +++ b/contents/split-operator_method/split-operator_method.md @@ -203,7 +203,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/stable_marriage_problem/stable_marriage_problem.md b/contents/stable_marriage_problem/stable_marriage_problem.md index 2e8850a01..dc7f031ab 100644 --- a/contents/stable_marriage_problem/stable_marriage_problem.md +++ b/contents/stable_marriage_problem/stable_marriage_problem.md @@ -68,7 +68,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/stacks_and_queues/stacks_and_queues.md b/contents/stacks_and_queues/stacks_and_queues.md index 89a77be9a..5d637deb3 100644 --- a/contents/stacks_and_queues/stacks_and_queues.md +++ b/contents/stacks_and_queues/stacks_and_queues.md @@ -35,7 +35,7 @@ Here is a simple implementation of a queue: ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/taylor_series_expansion/taylor_series_expansion.md b/contents/taylor_series_expansion/taylor_series_expansion.md index 29ba87be4..76effd506 100644 --- a/contents/taylor_series_expansion/taylor_series_expansion.md +++ b/contents/taylor_series_expansion/taylor_series_expansion.md @@ -51,7 +51,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/thomas_algorithm/thomas_algorithm.md b/contents/thomas_algorithm/thomas_algorithm.md index 81bb47617..607e9741a 100644 --- a/contents/thomas_algorithm/thomas_algorithm.md +++ b/contents/thomas_algorithm/thomas_algorithm.md @@ -147,7 +147,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/tree_traversal/tree_traversal.md b/contents/tree_traversal/tree_traversal.md index 5dc6657e0..566aca469 100644 --- a/contents/tree_traversal/tree_traversal.md +++ b/contents/tree_traversal/tree_traversal.md @@ -388,7 +388,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/contents/verlet_integration/verlet_integration.md b/contents/verlet_integration/verlet_integration.md index 80d719bef..5d993b4f4 100644 --- a/contents/verlet_integration/verlet_integration.md +++ b/contents/verlet_integration/verlet_integration.md @@ -234,7 +234,7 @@ MathJax.Hub.Queue(["Typeset",MathJax.Hub]); ##### Code Examples -The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/main/LICENSE.md)). ##### Text diff --git a/update_site.sh b/update_site.sh deleted file mode 100755 index 0ccf8f7bb..000000000 --- a/update_site.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -if [ $# -ge 1 ]; then - if [ $# -eq 2 ]; then - out_dir="$2" - else - if [ -z ${AAA_DIR+x} ]; then - echo "No output directory specified" - exit 1 - fi - out_dir="$AAA_DIR" - fi - - if [[ ! -d "$out_dir" ]]; then - echo "$out_dir is not a directory" - exit 1 - fi - - npm run build . /tmp/algorithm-archivists.github.io - - if [ $? -ne 0 ]; then - echo "Failed to build the book" - exit 1 - fi - - cd "$out_dir" - git reset --hard && \ - git clean -dfx && \ - git pull origin master - - if [ $? -ne 0 ]; then - echo "Failed to prepare repository" - exit 1 - fi - - cp -r /tmp/algorithm-archivists.github.io/* . - rm -r /tmp/algorithm-archivists.github.io - git add . - git commit -m "$1" - git push origin master - -else - echo "No commit message specified" -fi From 1eaaa06690c99c9385411b7ec74010470b7d4c9f Mon Sep 17 00:00:00 2001 From: James Schloss Date: Tue, 30 Nov 2021 16:35:19 +0100 Subject: [PATCH 093/146] adding histogram subsection for plotting chapter (#960) --- contents/plotting/code/gnuplot/histogram.gp | 22 +++++ contents/plotting/data/rand.dat | 100 ++++++++++++++++++++ contents/plotting/plotting.md | 40 +++++++- contents/plotting/res/gnuplot/histogram.png | Bin 0 -> 8844 bytes 4 files changed, 158 insertions(+), 4 deletions(-) create mode 100644 contents/plotting/code/gnuplot/histogram.gp create mode 100644 contents/plotting/data/rand.dat create mode 100644 contents/plotting/res/gnuplot/histogram.png diff --git a/contents/plotting/code/gnuplot/histogram.gp b/contents/plotting/code/gnuplot/histogram.gp new file mode 100644 index 000000000..9ef432236 --- /dev/null +++ b/contents/plotting/code/gnuplot/histogram.gp @@ -0,0 +1,22 @@ +# This is the size of each bin +bin_width = 1; + +# This takes the data and determins which bin id it should fall into +bin_id(x) = floor(x/bin_width) + +# This modifies each bin to be the correct width and also centers it over the +# correct number +bin(x) = bin_width * ( bin_id(x) + 0.5 ) + +# Starts the y-axis at 0 +set yrange [0:] + +# Removes legend +unset key + +# Sets a fill style for "fillsteps" +set style fill solid 1.00 border + +# The column number to be histogrammed is 1, change $1 to another number if +# you want to plot another column +plot '../../data/rand.dat' u (bin($1)):(1) t 'data' smooth frequency w fillsteps diff --git a/contents/plotting/data/rand.dat b/contents/plotting/data/rand.dat new file mode 100644 index 000000000..22608d0a6 --- /dev/null +++ b/contents/plotting/data/rand.dat @@ -0,0 +1,100 @@ +9 +6 +8 +8 +3 +7 +1 +4 +2 +9 +6 +1 +5 +1 +7 +3 +7 +4 +6 +5 +6 +1 +4 +6 +4 +8 +9 +3 +9 +9 +8 +3 +6 +9 +2 +1 +2 +1 +3 +6 +3 +1 +4 +1 +2 +9 +1 +4 +8 +2 +5 +5 +5 +1 +3 +2 +6 +3 +1 +6 +8 +5 +2 +1 +7 +8 +6 +1 +9 +2 +2 +4 +9 +5 +3 +1 +8 +7 +7 +8 +7 +3 +8 +1 +7 +5 +5 +5 +8 +6 +8 +9 +9 +1 +3 +8 +2 +6 +7 +3 diff --git a/contents/plotting/plotting.md b/contents/plotting/plotting.md index 0fd858f6b..c4bde1ecf 100644 --- a/contents/plotting/plotting.md +++ b/contents/plotting/plotting.md @@ -1,7 +1,7 @@ # Plotting Plotting is an essential tool for visualizing and understanding important details of several algorithms and methods and is necessary for studies in various areas of computational science. -For many languages, such as python, julia, and matlab, it is relatively straightforward to create simple plots for various types of data; however, for several other languages, like fortran, C/C++, and java, plotting can be a chore. +For many languages, such as python, julia, and matlab, it is relatively straightforward to create simple plots for various types of data; however, for several other languages, like Fortran, C/C++, and java, plotting can be a chore. Because the Algorithm Archive strives to be language agnostic, we do not want to favor any particular set of languages and have decided instead to output all data that needs plotting into a file format that can easily be read in by various plotting scripts separate from the algorithm implementations. If you are implementing any algorithm in a language found on this page, you should be able to modify your existing code to allow for on-the-fly plotting. @@ -485,7 +485,7 @@ In the case of two-dimensional image output, the data file be similar, but this [import](data/2d_sample_low_res.dat) -It is expected that the number of columns does not vary in each row and that we are working with an $$n \times m$$ matrix which can be simply plotted as a series of pixels that scale in color according to some defined colorbar. +It is expected that the number of columns does not vary in each row and that we are working with an $$n \times m$$ matrix which can be simply plotted as a series of pixels that scale in color according to some defined color bar. {% method %} {% sample lang="gnuplot" %} @@ -503,7 +503,7 @@ splot "sample_data.dat" matrix with image {% endmethod %} -#### changing the colorbar +#### changing the color bar For plotting images from data files, we will often need to specify how we color the image by setting a custom color bar @@ -537,7 +537,7 @@ For the purposes of the Algorithm Archive, this space is mainly two-dimensional; We will update this section if three-dimensional scatter plots are required. For the purposes of the Algorithm Archive, scatter plot data will be output as a series of $$x$$ and $$y$$ pairs, where each row has an $$x$$ and a $$y$$ value, separated by a tab character. -For example, a datafile might look like this: +For example, a data file might look like this: [import:1-10](data/scatterplot_data.dat) @@ -561,6 +561,37 @@ Here, we have chosen `pointtype 7`, simply because it is easier to see when comp {% endmethod %} +# Histograms + +Many different algorithms will output data as a series of points that must be organized into separate bins before anyone can make sense of the data. +For example, here are 10 values from a set of 100 randomly generated integers between 1 and 9: + +[import:50-60](data/rand.dat) + +Someone might ask, "How many 1s show up in this string of numbers?" +Similarly, someone might want to know how many 1s we have *in comparison* to the number of 2s (or 3s or 4s, etc). +To do this, we would create a set of bins and then iterate through the data, adding one to a bin every time we find a corresponding number. +Note that the bins do not necessarily need to be sequential integer values and that for floating point numbers, the input might need to be rounded. +You can even histograms objects or anything that else that can be categorized. + +For the data that we have shown above, we might create a histogram that looks like this: + +

+ +

+ +And here is a plotting script to generate it: + +{% method %} +[import](code/gnuplot/histogram.gp) +{% sample lang="gnuplot" %} + +For this, we are using a fill style to use with `fillsteps` so the histogram is colored, but if you just want a line, you could remove the fill style and use `histeps` instead. +As another note, we are using `t 'data' smooth frequency`, which essentially turns the input numbers into a small, binned array to plot. +{% endmethod %} + +Note that this code rounds the input in the case of floating point numbers. + If you are interested in seeing this type of plot generate fractal patterns, please look at the chapter on [iterated function systems](../IFS/IFS.md). ## Conclusions @@ -607,6 +638,7 @@ The text of this chapter was written by [James Schloss](https://github.com/leios - The image "[gnuplot_2d_sample](res/gnuplot/2d_sample.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). - The image "[gnuplot_2d_sample_colorbar](res/gnuplot/2d_sample_cb.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). - The image "[gnuplot_scatterplot](res/gnuplot/scatterplot.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). +- The image "[gnuplot_histogram](res/gnuplot/histogram.png)" was created by [James Schloss](https://github.com/leios) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). {% endmethod %} diff --git a/contents/plotting/res/gnuplot/histogram.png b/contents/plotting/res/gnuplot/histogram.png new file mode 100644 index 0000000000000000000000000000000000000000..5249f45eb958ef07bc0e3a945d4af81b070b71d8 GIT binary patch literal 8844 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 Vv(Hj`0)~r-`X!x*Pf literal 0 HcmV?d00001 From d6b372b74e33d9a795086523392c22d1a23ac963 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Tue, 30 Nov 2021 17:14:44 +0100 Subject: [PATCH 094/146] Fix barnsley rust code path (#952) --- contents/barnsley/barnsley.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index 6b2d6b3bf..625d72e8e 100644 --- a/contents/barnsley/barnsley.md +++ b/contents/barnsley/barnsley.md @@ -126,7 +126,7 @@ The biggest differences between the two code implementations is that the Barnsle {% sample lang="jl" %} [import, lang:"julia"](code/julia/barnsley.jl) {% sample lang="rs" %} -[import, lang:"rust"](code/rust/src/main.rs) +[import, lang:"rust"](code/rust/barnsley.rs) {% sample lang="cpp" %} [import, lang:"cpp"](code/cpp/barnsley.cpp) {% sample lang="c" %} From cf655b059534071cef5d66a5507586534b45cef1 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Wed, 1 Dec 2021 15:16:06 +0100 Subject: [PATCH 095/146] Fix warnings on size_t to int conversions (#933) --- contents/tree_traversal/code/cpp/tree_example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/tree_traversal/code/cpp/tree_example.cpp b/contents/tree_traversal/code/cpp/tree_example.cpp index 71a84c686..90271b58d 100644 --- a/contents/tree_traversal/code/cpp/tree_example.cpp +++ b/contents/tree_traversal/code/cpp/tree_example.cpp @@ -11,7 +11,7 @@ using std::size_t; struct node { std::vector children; - int value; + size_t value; }; // Simple recursive scheme for DFS From d51c940156603080e03c7331141e4c9cbbb623a1 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Wed, 1 Dec 2021 18:23:05 +0100 Subject: [PATCH 096/146] Fix import of coconut in flood_fill.md (#951) Fix import of coconut in flood_fill.md --- contents/flood_fill/flood_fill.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contents/flood_fill/flood_fill.md b/contents/flood_fill/flood_fill.md index 62348f107..3fb4f239c 100644 --- a/contents/flood_fill/flood_fill.md +++ b/contents/flood_fill/flood_fill.md @@ -95,7 +95,7 @@ In code, this might look like this: {% sample lang="py" %} [import:10-25, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} -[import:15-19, lang="coconut"](code/coconut/flood_fill.coco) +[import:15-20, lang="coconut"](code/coconut/flood_fill.coco) {% endmethod %} @@ -117,7 +117,7 @@ In code, it might look like this: {% sample lang="py" %} [import:55-63, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} -[import:54-63, lang:"coconut"](code/coconut/flood_fill.coco) +[import:52-61, lang:"coconut"](code/coconut/flood_fill.coco) {% endmethod %} The above code continues recursing through available neighbors as long as neighbors exist, and this should work so long as we are adding the correct set of neighbors. @@ -179,7 +179,7 @@ The code would look something like this: {% sample lang="py" %} [import:38-53, lang="python"](code/python/flood_fill.py) {% sample lang="coco" %} -[import:37-51, lang:"coconut"](code/coconut/flood_fill.coco) +[import:36-49, lang:"coconut"](code/coconut/flood_fill.coco) {% endmethod %} Now, there is a small trick in this code that must be considered to make sure it runs optimally. From 67a5cf027e3586d081b5d5fc5c9d09995c3ba14b Mon Sep 17 00:00:00 2001 From: stormofice <58337328+stormofice@users.noreply.github.com> Date: Wed, 1 Dec 2021 20:55:24 +0100 Subject: [PATCH 097/146] IFS: Standardize output files (#961) * Output 10000 points instead of 1000 in C implementation * Change output file from "out.dat" to "sierpinski.dat" in lisp * Change output file from "out.dat" to "sierpinski.dat" in Haskell * Introduce constant for the amount of points to generate Co-authored-by: James Schloss --- contents/IFS/code/c/IFS.c | 9 +++++---- contents/IFS/code/clisp/ifs.lisp | 2 +- contents/IFS/code/haskell/IFS.hs | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/contents/IFS/code/c/IFS.c b/contents/IFS/code/c/IFS.c index 99c4826be..e4aab3b50 100644 --- a/contents/IFS/code/c/IFS.c +++ b/contents/IFS/code/c/IFS.c @@ -29,16 +29,18 @@ void chaos_game(struct point *in, size_t in_n, struct point *out, } int main() { + const int point_count = 10000; + struct point shape_points [3] = {{0.0,0.0}, {0.5,sqrt(0.75)}, {1.0,0.0}}; - struct point out_points[1000]; + struct point out_points[point_count]; srand(time(NULL)); - chaos_game(shape_points, 3, out_points, 1000); + chaos_game(shape_points, 3, out_points, point_count); FILE *fp = fopen("sierpinksi.dat", "w+"); - for (int i = 0; i < 1000; ++i) { + for (int i = 0; i < point_count; ++i) { fprintf(fp, "%f\t%f\n", out_points[i].x, out_points[i].y); } @@ -46,4 +48,3 @@ int main() { return 0; } - diff --git a/contents/IFS/code/clisp/ifs.lisp b/contents/IFS/code/clisp/ifs.lisp index 4354ab54b..c9fc0e432 100644 --- a/contents/IFS/code/clisp/ifs.lisp +++ b/contents/IFS/code/clisp/ifs.lisp @@ -21,7 +21,7 @@ `((0 0) (0.5 ,(sqrt 0.75)) (1 0)))) ;; output the data to the "out.dat" file -(with-open-file (out "out.dat" :direction :output :if-exists :supersede) +(with-open-file (out "sierpinski.dat" :direction :output :if-exists :supersede) (flet ((format-point (p) ;; this is not very clean, but it's the simplest way to insert a tab into a string. (format nil "~f~c~f" (point-x p) #\tab (point-y p)))) diff --git a/contents/IFS/code/haskell/IFS.hs b/contents/IFS/code/haskell/IFS.hs index 9e8f4ef70..41d8b4c9a 100644 --- a/contents/IFS/code/haskell/IFS.hs +++ b/contents/IFS/code/haskell/IFS.hs @@ -27,4 +27,4 @@ main = do points = chaosGame g 10000 sierpinski showPoint (Point x y) = show x ++ "\t" ++ show y - writeFile "out.dat" $ intercalate "\n" $ map showPoint points + writeFile "sierpinski.dat" $ intercalate "\n" $ map showPoint points From 3bbc549cdea4c71e66a15b8dec61a9c7968b521f Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Thu, 2 Dec 2021 16:38:38 +0100 Subject: [PATCH 098/146] Fix warning on MSVC for barnsley C++ code (#943) Co-authored-by: James Schloss --- contents/barnsley/code/cpp/barnsley.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/contents/barnsley/code/cpp/barnsley.cpp b/contents/barnsley/code/cpp/barnsley.cpp index 88fb24766..491d6bd51 100644 --- a/contents/barnsley/code/cpp/barnsley.cpp +++ b/contents/barnsley/code/cpp/barnsley.cpp @@ -75,6 +75,7 @@ auto select_array( rnd -= probabilities[i]; } assert(!static_cast("check if probabilities adding up to 1")); + return hutchinson_op[0]; } // This is a general function to simulate a chaos game From fca9911a7c1cf44fd4bc79e850e021a6c385f3eb Mon Sep 17 00:00:00 2001 From: PaddyKe <34421580+PaddyKe@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:52:03 +0100 Subject: [PATCH 099/146] Added Iterated function system in PowerShell (#895) * implemented IFS in PowerShell * fixed typo Co-authored-by: James Schloss --- contents/IFS/IFS.md | 4 ++++ contents/IFS/code/powershell/IFS.ps1 | 34 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 contents/IFS/code/powershell/IFS.ps1 diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index cd503ae46..f7d017e36 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -146,6 +146,8 @@ Here, instead of tracking children of children, we track a single individual tha [import:4-16, lang:"coconut"](code/coconut/IFS.coco) {% sample lang="java" %} [import:16-39, lang:"java"](code/java/IFS.java) +{% sample lang="ps1" %} +[import:2-19, lang:"powershell"](code/powershell/IFS.ps1) {% endmethod %} If we set the initial point to the on the equilateral triangle we saw before, we can see the Sierpinski triangle again after a few thousand iterations, as shown below: @@ -232,6 +234,8 @@ In addition, we have written the chaos game code to take in a set of points so t [import, lang:"coconut"](code/coconut/IFS.coco) {%sample lang="java" %} [import, lang:"java"](code/java/IFS.java) +{% sample lang="ps1" %} +[import, lang:"powershell"](code/powershell/IFS.ps1) {% endmethod %} ### Bibliography diff --git a/contents/IFS/code/powershell/IFS.ps1 b/contents/IFS/code/powershell/IFS.ps1 new file mode 100644 index 000000000..086c80072 --- /dev/null +++ b/contents/IFS/code/powershell/IFS.ps1 @@ -0,0 +1,34 @@ +# This function simulates a "chaos game" +function Simulate-ChaosGame($n, $shapePoints) { + $outputPoints = New-Object System.Collections.ArrayList + + # Initialize the starting point + $point = @($(Get-Random -Minimum 0.0 -Maximum 1.0), $(Get-Random -Minimum 0.0 -Maximum 1.0)) + + for ($i = 0; $i -lt $n; $i++) { + $outputPoints.add($point) | Out-Null + $temp = $shapePoints[$(Get-Random -Maximum $shapePoints.Count)] + + $point = @( + 0.5 * ($point[0] + $temp[0]) + 0.5 * ($point[1] + $temp[1]) + ) + } + + return $outputPoints +} + + +# This will generate a Sierpinski triangle with a chaos game of n points for an +# initial triangle with three points on the vertices of an equilateral triangle: +# A = (0.0, 0.0) +# B = (0.5, sqrt(0.75)) +# C = (1.0, 0.0) +# It will output the file sierpinski.dat, which can be plotted after +$shapePoints = @( + @(0.0, 0.0), + @(0.5, [math]::sqrt(0.75)), + @(1.0, 0.0) +) + +Simulate-ChaosGame -n 10000 -shapePoints $shapePoints | % { "$($_[0])`t$($_[1])" } | Out-File -Path "sierpinski.dat" From a3276bedd94ea7cee587bb565c351c405e9b86b9 Mon Sep 17 00:00:00 2001 From: PaddyKe <34421580+PaddyKe@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:54:26 +0100 Subject: [PATCH 100/146] Add Approximate counting in Java (#898) * added approximative counting in java * added code examples to markdown files * fixed typo * fixed indentation * fixed typos * fixed printed comments * added failed message * Update contents/approximate_counting/code/java/ApproximateCounting.java Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> Co-authored-by: James Schloss Co-authored-by: stormofice <58337328+stormofice@users.noreply.github.com> --- .../approximate_counting.md | 2 + .../code/java/ApproximateCounting.java | 85 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 contents/approximate_counting/code/java/ApproximateCounting.java diff --git a/contents/approximate_counting/approximate_counting.md b/contents/approximate_counting/approximate_counting.md index 5e06e43b5..e5b7c1f5e 100644 --- a/contents/approximate_counting/approximate_counting.md +++ b/contents/approximate_counting/approximate_counting.md @@ -366,6 +366,8 @@ As we do not have any objects to count, we will instead simulate the counting wi [import, lang:"cpp"](code/cpp/approximate_counting.cpp) {% sample lang="python" %} [import, lang:"python"](code/python/approximate_counting.py) +{% sample lang="java" %} +[import, lang:"java"](code/java/ApproximateCounting.java) {% endmethod %} ### Bibliography diff --git a/contents/approximate_counting/code/java/ApproximateCounting.java b/contents/approximate_counting/code/java/ApproximateCounting.java new file mode 100644 index 000000000..2dd49c0f0 --- /dev/null +++ b/contents/approximate_counting/code/java/ApproximateCounting.java @@ -0,0 +1,85 @@ +import java.lang.Math; +import java.util.stream.DoubleStream; + +public class ApproximateCounting { + + /* + * This function taks + * - v: value in register + * - a: a scaling value for the logarithm based on Morris's paper + * It returns the approximate count + */ + static double n(double v, double a) { + return a * (Math.pow(1 + 1 / a, v) - 1); + } + + + /* + * This function takes + * - v: value in register + * - a: a scaling value for the logarithm based on Morris's paper + * It returns the new value for v + */ + static double increment(double v, double a) { + double delta = 1 / (n(v + 1, a) - n(v, a)); + + if (Math.random() <= delta) { + return v + 1; + } else { + return v; + } + } + + + + /* + * This function takes + * - v: value in register + * - a: a scaling value for the logarithm based on Morris's paper + * It returns the new value for v + */ + static double approximateCount(int nItems, double a) { + double v = 0; + + for (int i = 0; i < nItems; i++) { + v = increment(v, a); + } + + return n(v, a); + } + + /* + * This function takes + * - nTrials: the number of counting trails + * - nItems: the number of items to count + * - a: a scaling value for the logarithm based on Morris's paper + * - threshold: the maximum percent error allowed + * It terminates the program on failure + */ + static void testApproximateCount(int nTrials, int nItems, double a, double threshold) { + double avg = DoubleStream.generate(() -> approximateCount(nItems, a)) + .limit(nTrials) + .average() + .getAsDouble(); + + if (Math.abs((avg - nItems) / nItems) < threshold) { + System.out.println("passed"); + } else { + System.out.println("failed"); + } + } + + + public static void main(String args[]) { + System.out.println("[#]\nCounting Tests, 100 trials"); + System.out.println("[#]\ntesting 1,000, a = 30, 10% error"); + testApproximateCount(100, 1_000, 30, 0.1); + + System.out.println("[#]\ntesting 12,345, a = 10, 10% error"); + testApproximateCount(100, 12_345, 10, 0.1); + + System.out.println("[#]\ntesting 222,222, a = 0.5, 20% error"); + testApproximateCount(100, 222_222, 0.5, 0.2); + } + +} From aa83fecb8fa4cd5508b362b62af6fa9f3b6a1e64 Mon Sep 17 00:00:00 2001 From: PeanutbutterWarrior <50717143+PeanutbutterWarrior@users.noreply.github.com> Date: Thu, 2 Dec 2021 16:18:34 +0000 Subject: [PATCH 101/146] Implement Stacks and Queues in Rust. (#924) * Implement Stack * Implement Queue * Update markdown page * Add comments with output of prints * Use equivalent methods instead of reimplementing them * Add SConscript file Co-authored-by: James Schloss --- CONTRIBUTORS.md | 5 ++- contents/stacks_and_queues/code/rust/Queue.rs | 43 +++++++++++++++++++ .../stacks_and_queues/code/rust/SConscript | 10 +++++ contents/stacks_and_queues/code/rust/Stack.rs | 41 ++++++++++++++++++ .../stacks_and_queues/stacks_and_queues.md | 4 ++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 contents/stacks_and_queues/code/rust/Queue.rs create mode 100644 contents/stacks_and_queues/code/rust/SConscript create mode 100644 contents/stacks_and_queues/code/rust/Stack.rs diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 82f3c173a..fc3113ecc 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -51,7 +51,7 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Vincent Zalzal - Jonathan D B Van Schenck - James Goytia -- Sammy Plat +- Sammy Plat - Jonathan Dönszelmann - Ishaan Verma - Delphi1024 @@ -60,4 +60,5 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Ridham177 - Hugo Salou - Dimitri Belopopsky -+ Henrik Abel Christensen +- Henrik Abel Christensen +- Peanutbutter_Warrior diff --git a/contents/stacks_and_queues/code/rust/Queue.rs b/contents/stacks_and_queues/code/rust/Queue.rs new file mode 100644 index 000000000..0f432e621 --- /dev/null +++ b/contents/stacks_and_queues/code/rust/Queue.rs @@ -0,0 +1,43 @@ +use std::collections::VecDeque; + +struct Queue { + list: VecDeque +} + +impl Queue { + fn new() -> Self { + Queue{ + list: VecDeque::new(), + } + } + + // Note that this returns a reference to the value + // This is in contrast to dequeue which gives ownership of the value + fn front(&self) -> Option<&T> { + self.list.front() + } + + fn dequeue(&mut self) -> Option { + self.list.pop_front() + } + + fn enqueue(&mut self, item: T) { + self.list.push_back(item); + } + + fn size(&self) -> usize { + self.list.len() + } +} + +fn main() { + let mut i32queue = Queue::new(); + + i32queue.enqueue(4); + i32queue.enqueue(5); + i32queue.enqueue(6); + + println!("{:?}", i32queue.dequeue().unwrap()); // 4 + println!("{:?}", i32queue.size()); // 2 + println!("{:?}", i32queue.front().unwrap()); // 5 +} diff --git a/contents/stacks_and_queues/code/rust/SConscript b/contents/stacks_and_queues/code/rust/SConscript new file mode 100644 index 000000000..0c3f15913 --- /dev/null +++ b/contents/stacks_and_queues/code/rust/SConscript @@ -0,0 +1,10 @@ +Import('*') +from pathlib import Path + +dirname = Path.cwd().parents[1].stem + +env.rustc(f'#/build/rust/stack', '#/contents/stacks_and_queues/code/rust/Stack.rs') +env.Clean('rust', f'#/build/rust/stack.pdb') + +env.rustc(f'#/build/rust/queue', '#/contents/stacks_and_queues/code/rust/Queue.rs') +env.Clean('rust', f'#/build/rust/queue.pdb') \ No newline at end of file diff --git a/contents/stacks_and_queues/code/rust/Stack.rs b/contents/stacks_and_queues/code/rust/Stack.rs new file mode 100644 index 000000000..13010c3f0 --- /dev/null +++ b/contents/stacks_and_queues/code/rust/Stack.rs @@ -0,0 +1,41 @@ +struct Stack { + list: Vec +} + +impl Stack { + fn new() -> Self { + Stack { + list: Vec::new(), + } + } + + // Note that this returns a reference to the value + // This is in contrast to pop which gives ownership of the value + fn top(&self) -> Option<&T> { + self.list.last() + } + + fn pop(&mut self) -> Option { + self.list.pop() + } + + fn push(&mut self, item: T) { + self.list.push(item); + } + + fn size(&self) -> usize { + self.list.len() + } +} + +fn main() { + let mut i32stack: Stack = Stack::new(); + + i32stack.push(4); + i32stack.push(5); + i32stack.push(6); + + println!("{:?}", i32stack.pop().unwrap()); // 6 + println!("{:?}", i32stack.size()); // 2 + println!("{:?}", i32stack.top().unwrap()); // 5 +} diff --git a/contents/stacks_and_queues/stacks_and_queues.md b/contents/stacks_and_queues/stacks_and_queues.md index 5d637deb3..a3c46b478 100644 --- a/contents/stacks_and_queues/stacks_and_queues.md +++ b/contents/stacks_and_queues/stacks_and_queues.md @@ -20,6 +20,8 @@ Here is a simple implementation of a stack: [import, lang:"typescript"](code/typescript/stack.ts) {% sample lang="java" %} [import, lang:"java"](code/java/Stack.java) +{% sample lang="rust" %} +[import, lang:"rust"](code/rust/Stack.rs) {% endmethod %} Here is a simple implementation of a queue: @@ -28,6 +30,8 @@ Here is a simple implementation of a queue: [import, lang:"typescript"](code/typescript/queue.ts) {% sample lang="java" %} [import, lang:"java" ](code/java/Queue.java) +{% sample lang="rust" %} +[import, lang:"rust" ](code/rust/Queue.rs) {% endmethod %} From ffaa8901c27607f25a868a12837d2b27671199cf Mon Sep 17 00:00:00 2001 From: Nicholas Tindle Date: Thu, 2 Dec 2021 13:01:44 -0600 Subject: [PATCH 102/146] Use Scons in CI with container (#959) Use Scons with the container Co-authored-by: Sammy Plat Co-authored-by: James Schloss --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d25ca4d3..3ed45c6c1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,12 @@ on: pull_request jobs: build: runs-on: ubuntu-latest + container: + options: --entrypoint /bin/bash --user 0 + image: ghcr.io/algorithm-archivists/aaa-langs:latest + defaults: + run: + shell: bash --rcfile /root/.bashrc -eo pipefail {0} steps: - name: Checkout uses: actions/checkout@v2 @@ -14,3 +20,10 @@ jobs: run: | npm install npx honkit build + + - name: Initalize cargo and run SCons + env: + HOME: /root + run: | + . "$HOME/.cargo/env" + scons -Q From 05e97580b2ee00b0dae20c94a8e7c51352d064ef Mon Sep 17 00:00:00 2001 From: Shudipto <32040453+shudipto-amin@users.noreply.github.com> Date: Fri, 3 Dec 2021 08:25:04 -0500 Subject: [PATCH 103/146] New chapter "Metropolis" with Python Implementation (#929) * Add new chapter: metropolis_hastings; in python * Add markdown and python files for metropolis * Add image for metropolis * Update .gitignore, SUMMARY.md, and metropolis * Untrack .ipynb_checkpoints * Untrack ipynb_checkpoints * Fix algorithm steps list * Really fix markdown list * Add plot of P to chapter * Add metropolis animation and update plot of P(x) * Add minor update to chapter text * Generate gif and mp4 for random walk * Complete first draft! * Final version before Pull Request * Add metropolis citation * Remove unnecessary lines from code and bib file * Fix display of code in md * Fix random walk capitalization. * Apply Amaras' suggestions from code review This commit makes minor edits which resolve conflicts with PEP8 and improve readability of code. It also makes chapter sub-chapter of Monte Carlo. Co-authored-by: James Schloss Co-authored-by: Sammy Plat * Fix the code import lines in md file. * Change to in metropolis.py * Add probability section to metropolis.md However, this is temporary, as this section needs to go into a separate chapter. * Move Probability section in metropolis to own chapter. * Fix SUMMARY.md spelling mistake from previous commit * Add figures for probability distribution chapter * Update image of normal distribution * Finish first draft of probability chapter * Minor edits to distributions.md. * "Minor changes to distributions.md" * Complete the Example/Application section of metropolis. * Address most issues in review of PR#929 * Application sections created. * g() definition moved up to a better place * More discussion on g. * Missing citations provided * Clarity provided (hopefully) * Add image of 1D_particles * Update citations in md file * Add testing function to metropolis python code. Also modifies markdown to describe test. Also adds citation for RMSD. * Numpyfy metropolis f function and fix errors. * Implement generator to iterate. * Reformat output of test and nrmsd error reporting. * Add description of video and fix code display. * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Update contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Put sentences in `metropolis.md` on separate lines. * Put sentences in distributions.md chapter on separate lines. * Addresses issues raised by Leios' 1st review of probability chapter. * Adds intro to beginning. * Fixes plurality of die. * Clarifies some notation in discrete section. * Removes explanation of calculus. * Other minor edits. * Add minor edits. * Update contents/metropolis/metropolis.md title Co-authored-by: James Schloss * Simplify intro to contents/metropolis/metropolis.md Co-authored-by: James Schloss * Minor formatting to contents/metropolis/metropolis.md Co-authored-by: James Schloss * Fix spelling contents/metropolis/metropolis.md Co-authored-by: James Schloss * Simplify line 71 of contents/metropolis/metropolis.md Co-authored-by: James Schloss * Update contents/metropolis/metropolis.md Co-authored-by: James Schloss * Update example application in metropolis according to Leios comments. * Minor edit: contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Minor edit: contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Minor edit: contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Minor edit: contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Minor edit: contents/probability/distributions/distributions.md Co-authored-by: James Schloss * Apply minor suggestions from Leios' code review Mostly typos, spelling, punctuation, and grammar. Co-authored-by: James Schloss * Add minor edits from code Leios' review * Add minor edit * Apply minor edit suggestions from Leios Mostly punctuation and grammar. Co-authored-by: James Schloss * Add minor formatting, such as periods after equations. * Fix integer interval notation using hack. * Add minor edits missed previously in probability chapter. * Add minor edits to metropolis, mostly punctuation. * Apply minor edits from Leios Mostly grammar and sentence structure. Co-authored-by: James Schloss * Add intro line to Algorithm section of metropolis. * Add name to contributor.md * Apply suggestions from Leios * Minor edits for grammar and clarity. * Applies to both metropolis and probablity chapters. Co-authored-by: James Schloss * Apply suggestions from code review Co-authored-by: Shudipto <32040453+shudipto-amin@users.noreply.github.com> Co-authored-by: Kazi Shudipto Amin Co-authored-by: James Schloss Co-authored-by: Sammy Plat --- .gitignore | 2 +- CONTRIBUTORS.md | 1 + SUMMARY.md | 2 + contents/metropolis/code/python/metropolis.py | 90 ++++++ contents/metropolis/metropolis.md | 283 ++++++++++++++++++ contents/metropolis/res/1D_particles.png | Bin 0 -> 23564 bytes .../metropolis/res/animated_metropolis.gif | Bin 0 -> 1647776 bytes .../metropolis/res/animated_metropolis.mp4 | Bin 0 -> 577837 bytes .../metropolis/res/animated_random_walk.gif | Bin 0 -> 42487 bytes .../metropolis/res/animated_random_walk.mp4 | Bin 0 -> 20682 bytes .../metropolis/res/multiple_histograms.png | Bin 0 -> 191289 bytes contents/metropolis/res/plot_of_P.png | Bin 0 -> 158010 bytes .../distributions/distributions.md | 214 +++++++++++++ .../res/double_die_frequencies.png | Bin 0 -> 96012 bytes .../distributions/res/normal_distribution.png | Bin 0 -> 206149 bytes literature.bib | 101 +++++++ 16 files changed, 692 insertions(+), 1 deletion(-) create mode 100644 contents/metropolis/code/python/metropolis.py create mode 100644 contents/metropolis/metropolis.md create mode 100644 contents/metropolis/res/1D_particles.png create mode 100644 contents/metropolis/res/animated_metropolis.gif create mode 100644 contents/metropolis/res/animated_metropolis.mp4 create mode 100644 contents/metropolis/res/animated_random_walk.gif create mode 100644 contents/metropolis/res/animated_random_walk.mp4 create mode 100644 contents/metropolis/res/multiple_histograms.png create mode 100644 contents/metropolis/res/plot_of_P.png create mode 100644 contents/probability/distributions/distributions.md create mode 100644 contents/probability/distributions/res/double_die_frequencies.png create mode 100644 contents/probability/distributions/res/normal_distribution.png diff --git a/.gitignore b/.gitignore index 09a7ab178..5e1e79300 100644 --- a/.gitignore +++ b/.gitignore @@ -478,7 +478,7 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc - +*.ipynb_checkpoints* # Cake - Uncomment if you are using it # tools/** # !tools/packages.config diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index fc3113ecc..ca16b50f9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -61,4 +61,5 @@ This file lists everyone, who contributed to this repo and wanted to show up her - Hugo Salou - Dimitri Belopopsky - Henrik Abel Christensen +- K. Shudipto Amin - Peanutbutter_Warrior diff --git a/SUMMARY.md b/SUMMARY.md index 4d4597b1c..644fccc56 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -20,9 +20,11 @@ * [Multiplication as a Convolution](contents/convolutions/multiplication/multiplication.md) * [Convolutions of Images (2D)](contents/convolutions/2d/2d.md) * [Convolutional Theorem](contents/convolutions/convolutional_theorem/convolutional_theorem.md) + * [Probability Distributions](contents/probability/distributions/distributions.md) * [Tree Traversal](contents/tree_traversal/tree_traversal.md) * [Euclidean Algorithm](contents/euclidean_algorithm/euclidean_algorithm.md) * [Monte Carlo](contents/monte_carlo_integration/monte_carlo_integration.md) + * [Metropolis](contents/metropolis/metropolis.md) * [Matrix Methods](contents/matrix_methods/matrix_methods.md) * [Gaussian Elimination](contents/gaussian_elimination/gaussian_elimination.md) * [Thomas Algorithm](contents/thomas_algorithm/thomas_algorithm.md) diff --git a/contents/metropolis/code/python/metropolis.py b/contents/metropolis/code/python/metropolis.py new file mode 100644 index 000000000..a4fc29794 --- /dev/null +++ b/contents/metropolis/code/python/metropolis.py @@ -0,0 +1,90 @@ +import numpy as np + + +def f(x, normalize=False): + ''' + Function proportional to target distribution, a sum of Gaussians. + For testing, set normalize to True, to get target distribution exactly. + ''' + # Gaussian heights, width parameters, and mean positions respectively: + a = np.array([10., 3., 1.]).reshape(3, 1) + b = np.array([ 4., 0.2, 2.]).reshape(3, 1) + xs = np.array([-4., -1., 5.]).reshape(3, 1) + + if normalize: + norm = (np.sqrt(np.pi) * (a / np.sqrt(b))).sum() + a /= norm + + return (a * np.exp(-b * (x - xs)**2)).sum(axis=0) + +def g(): + '''Random step vector.''' + return np.random.uniform(-1,1) + +def metropolis_step(x, f=f, g=g): + '''Perform one full iteration and return new position.''' + + x_proposed = x + g() + a = min(1, (f(x_proposed) / f(x)).item()) + + x_new = np.random.choice([x_proposed, x], p=[a, 1-a]) + + return x_new + +def metropolis_iterate(x0, num_steps): + '''Iterate metropolis algorithm for num_steps using iniital position x_0''' + + for n in range(num_steps): + if n == 0: + x = x0 + else: + x = metropolis_step(x) + yield x + + +def test_metropolis_iterate(num_steps, xmin, xmax, x0): + ''' + Calculate error in normalized density histogram of data + generated by metropolis_iterate() by using + normalized-root-mean-square-deviation metric. + ''' + + bin_width = 0.25 + bins = np.arange(xmin, xmax + bin_width/2, bin_width) + centers = np.arange(xmin + bin_width/2, xmax, bin_width) + + true_values = f(centers, normalize=True) + mean_value = np.mean(true_values - min(true_values)) + + x_dat = list(metropolis_iterate(x0, num_steps)) + heights, _ = np.histogram(x_dat, bins=bins, density=True) + + nmsd = np.average((heights - true_values)**2 / mean_value) + nrmsd = np.sqrt(nmsd) + + return nrmsd + + + +if __name__ == "__main__": + xmin, xmax = -10, 10 + x0 = np.random.uniform(xmin, xmax) + + num_steps = 50_000 + + x_dat = list(metropolis_iterate(x0, 50_000)) + + # Write data to file + output_string = "\n".join(str(x) for x in x_dat) + + with open("output.dat", "w") as out: + out.write(output_string) + out.write("\n") + + + # Testing + print(f"Testing with x0 = {x0:5.2f}") + print(f"{'num_steps':>10s} {'NRMSD':10s}") + for num_steps in (500, 5_000, 50_000): + nrmsd = test_metropolis_iterate(num_steps, xmin, xmax, x0) + print(f"{num_steps:10d} {nrmsd:5.1%}") diff --git a/contents/metropolis/metropolis.md b/contents/metropolis/metropolis.md new file mode 100644 index 000000000..961f1b14d --- /dev/null +++ b/contents/metropolis/metropolis.md @@ -0,0 +1,283 @@ +# The Metropolis Algorithm + +The [Monte Carlo Integration](../monte_carlo_integration/monte_carlo_integration.html) method uses random numbers to approximate the area of pretty much any shape we choose. +The Metropolis algorithm {{ "metropolis1953equation" | cite }} is a slightly more advanced Monte Carlo method which uses random numbers to approximate a [probability distribution](../probability/distributions/distributions.md): + +$$ +P(\mathbf{x}) = \frac{f(\mathbf{x})}{\displaystyle\int_D f(\mathbf{x})d\mathbf{x}}, +$$ + +where $$D$$ is the domain of $$P(\mathbf{x})$$, i.e., all possible values of the $$\mathbf{x}$$ for which $$P(\mathbf{x})$$ is defined. +$$f(\mathbf{x})$$ is a function that is proportional to $$P(x)$$, such as a statistical frequency distribution which counts the number of occurences of each $$\mathbf{x}$$. +The integral in the denominator is the __normalization factor__ which ensures that the sum of all probabilities is unity, i.e., +$$ +\int_D P(\mathbf{x}) d\mathbf{x} = 1. +$$ +A one-dimensional example is the __normal distribution__, or __Gaussian distribution__, given by + +$$ +P(x) = \frac{e^{-x^2}}{\displaystyle\int_{-\infty}^{\infty} e^{-x^2} dx} = \frac{1}{\sqrt{\pi}} e^{-x^2}. +$$ + + +In practice, it's often easy for us to know $$f(x)$$, but the integral in the denominator can be quite difficult to calculate, even numerically. +This is especially true when the coordinates ($$\mathbf{x}$$) are multidimensional, and $$f(\mathbf{x})$$ is an expensive calculation, as we shall see in the examples below. + +## An example application + +One example of a complicated probability function arises when considering a physical system of $$N$$ particles. +These could be atoms, molecules, or even star systems! +For such systems, we can usually describe the __potential energy__ {{ "potential_energy_wiki" | cite }} of the system as a function of the coordinates of all particles, $$\mathbf{x}$$, + +$$ +E(\mathbf{x}) = E(x_1, y_1, z_1, x_2, y_2, z_2, ... ,x_N, y_N, z_N), +$$ + +where $$x_i, y_i, z_i$$ are the spatial coordinates of particle $$i$$. +So altogether there are $$3N$$ coordinates – making $$E(\mathbf{x})$$ a $$3N$$ dimensional function, which can be a computationally intensive calculation on it's own. But it doesn't end there! + +The physicist Ludwig Boltzmann {{ "ludwig_boltzmann_wiki" | cite }} discovered that when such a system is in equilibrium at some temperature $$T$$, you can describe the probability density of the system for any set of coordinates $$\mathbf{x}$$ using, {{ "boltzmann_distribution_wiki" | cite }} + +$$ +P(\mathbf{x}) = \frac{\displaystyle \exp\left[{\displaystyle\frac{-E(\mathbf{x})}{T} } \right]} {Q}, +$$ + +where the numerator is called the __Boltzmann factor__, and $$Q$$ is the [normalization constant](../probability/distributions/distributions.md), + +$$ +Q = \int_D \exp\left[{\displaystyle\frac{-E(\mathbf{x})}{T} } \right] d\mathbf{x}. +$$ + +We can see now that the probability density function is a difficult calculation, particularly because of $$Q$$. +Almost always, no analytical solution exists to the integral in $$Q$$, and the numerical integration is unfeasible. + +To see that $$Q$$ is unfeasible to calculate, imagine there are just $$10$$ particles which all exist in a $$1$$D world, restricted to a line segment. + +

+ <FIG> 1D particles +

+ +Let's assume that the particles _interact_, meaning that the position of one particle affects that of another. +This could be the case, for example, if all the particles were charged, and so they would be repelling or attracting each other. +This means that the energy $$E(\mathbf{x}) = E(x_1,...,x_{10})$$ of the system is a $$10$$D function, and it would not be possible to simplify it any further due to the interactions. +Thus, the Boltzmann factor, $$\exp\left[-E(\mathbf{x})/T\right]$$, is also a $$10$$D function. To calculate $$Q$$, we would have to integrate the Boltzmann factor $$10$$ times, one for each coordinate, + +$$ +Q = \int_{x_1} \dots \int_{x_{10}} \exp\left[\frac{-E(x_1,\dots x_{10})}{T}\right]\ dx_1\dots dx_{10}. +$$ + +In most cases, there is no known analytical expression for the above integral, so it has to be done numerically. +To do so, imagine that we divide the $$1$$D line segment into only $$50$$ different intervals, allowing each particle to take on $$50$$ different positions. +This is equivalent to dividing the length of a football field into intervals of about $$2$$ meters – not a resolution you'd wanna watch a game in! +Even with such poor resolution, the number of different combinations of positions is $$10^{50}$$ – a colossal number indeed. +To see how large this number is, imagine that a single computation of $$E(\mathbf{x})$$ took only $$1$$ nanosecond on a single processor, which is much faster than most energy calculations for physical systems in practice. + With that speed, it would require $$10^{41}$$ seconds on a single processor to calculate $$Q$$ – which means that _even_ with all the processors in the world running in parallel (there could be billions or trillions of them), calculating $$Q$$ would still take longer than the age of the universe – by many orders of magnitude! + +What's really powerful about the Metropolis approach is that you don't need to know the probability function itself. +Instead, you just need a function which is _proportional_ to it. +What this means for the Boltzmann distribution is that you only need to know the term, + +$$ +f(\mathbf{x}) = \exp\left[{\displaystyle\frac{-E(\mathbf{x})}{T} } \right]. +$$ + +The Metropolis algorithm can bypass the calculation of $$Q$$ altogether and use $$f(x)$$ to generate a distribution of $$x$$ which follows the probability density $$P(x)$$. +In other words, it can sample values of $$x$$ in such away that the probability of sampling $$x$$ will follow the actual distribution $$P(x)$$. +Thus, if Metropolis was used to sample from $$x$$, the number of occurences of $$x$$ would be proportional to $$P(x)$$. +Numerical normalization can then be done by using the total number of samples instead of performing an integration. +This fact dramatically reduces the number of calculations needed to approximate the probability distribution. + +Finally, the Metropolis algorithm can be modified or implemented in other methods, and forms the basis of many advanced sampling algorithms. +The most popular is probably the Metropolis-Hastings algorithm {{ "hastings1970monte" | cite }} which is fundamentally the same. +Some other algorithms that use this method are Metropolis-adjusted Langevin algorithm {{ "mala_wiki" | cite }}, and Hamiltonian Monte Carlo {{ "hmc_wiki" | cite }}, to name a few. +They are often used for physical systems that follow a Boltzmann distribution. + + +## A Random Walk in One Dimension + +In the rest of this chapter, we will look at $$1$$D examples to understand the Metropolis algorithm. +Although the algorithm is not particularly efficient in just one dimension, it is much easier to understand in one dimension than in multiple dimensions. +The Metropolis algorithm is very similar to a random walk, so let's first see how we can get a distribution from a random walk. + +
+ +
+ +The dot in the figure above is a "walker", whose initial position is $$x=0$$. +The step size, $$g$$, is a random number in the interval $$(-1, 1)$$. +To get the next position of the walker, we simply generate $$g$$ and add it to the current position. +To get a distribution of $$x$$ from this walk, we can divide the domain into discrete locations or "bins" and count how often the walker visits each bin. +Each time it visits a bin, the frequency for that bin goes up by one. +Over many iterations, we get a frequency distribution of $$x$$. + +## A Random Walk With an Acceptance Criterion + +The Metropolis algorithm works in a similar way to the random walk, but differs crucially in one way – after choosing a random step for the walker, a decision is made about whether to __accept__ or __reject__ the step based on the function $$f(x)$$. +To understand how this works, let's call $$x_t$$ the position before the step, and $$x'$$ the position after it. +We then define the probability of __accepting the step__ to be + +$$ +A = \min \left(\frac{f(x')}{f(x_t)}, 1\right). +$$ + +The $$\min$$ function above implies that $$A=1$$ if $$f(x') \gt f(x_t)$$, which means that the move will __always__ be accepted if it is toward a higher probability position. +Otherwise, it will be accepted with a probability of $$f(x') / f(x_t)$$. +If we create a histogram of this walk for some arbitrary target function $$P(x)$$, we can see from the figure below that the frequency starts to look very much like it after many iterations! + +
+ +
+ +Although convergence occurs eventually, not all parts of the distribution achieve convergence quickly. +Note from the animation above, that the walker very quickly replicates the distribution of the two peaks on the left, but takes quite a while to even reach the third peak to the right. +This is because there is a long low probability region between the third peak and second peak that acts as a "barrier." +This may not necessarily be a bad thing – sometimes one might want to estimate how long something takes to transition from one state to another, and often these peaks represent such 'states'. +So averaging over many metropolis runs may give some estimate of these transition times. +If global sampling is the goal, the process of exploration could be sped up by choosing larger step sizes for the walker, for example by choosing step size $$g$$ from an interval like $$(-3,3)$$ instead of $$(-1,1)$$. + + +## The Algorithm for a One Dimensional Example + +Now let's dive into the actual algorithm with some example code! + +### The Initial Setup + +Let our target distribution be +$$ +P(x) = \frac{f(x)}{\int_{-10}^{10} f(x)}, +$$ + +where $$f(x)$$ is the same function we have shown above and is given by +$$ +f(x) = 10e^{-4(x+4)^2} + 3e^{-0.2(x+1)^2} + e^{-2(x-5)^2}. +$$ + +The code for defining this function is given below. + +{% method %} +{% sample lang="py" %} +[import:4-18, lang:"python"](code/python/metropolis.py) +{% endmethod %} + +Since this is an easy function to integrate, and hence get our target distribution $$P(x)$$ directly, we can use it to verify the Metropolis algorithm. +The plot of $$P(x)$$ in the figure below shows three different peaks of varying width and height, with some overlap as well. + +

+ <FIG> Plot of P(x) +

+ +Next, we define our walker's symmetric step generating function. +As in the random walk example, we will use a random real number between $$-1$$ and $$+1$$ as the step size. + +{% method %} +{% sample lang="py" %} +[import:20-22, lang:"python"](code/python/metropolis.py) +{% endmethod %} + +However, $$g$$ can be any function symmetric about $$0$$ for the above algorithm to work. +For example, it can be a number chosen randomly from a discrete list, such as $$[ -3, -1, -1, +1, +1, +3]$$. +It can also be a number chosen from a symmetric continuos distribution, like the Gaussian, $$e^{-x^2}$$. +In higher dimensions, the function should be spherically symmetric, such as a multidimensional Gaussian function, $$e^{-(x^2 +y^2 + ...)}$$. +Whatever function you choose, there are at least a couple of things to note: +1. If the function $$g$$ is discrete, you will only sample discrete values. +For example, if $$g$$ returns only $$-1$$ or $$+1$$, and nothing in between, you will sample only integer steps away from the initial $$x_0$$. +2. The average step size really matters! +A small step-size means the walker will carefully sample nearby regions more, but will walk more slowly, so might not be good at exploring far and wide. +On the other hand, a walker with a large step size may not sample nearby regions accurately – and actually has a higher chance of being rejected if the walker is already in a high probability region, since the acceptance ratio is more drastic for large steps. +The effect of step-size on the walker's efficiency is far from obvious! + +The question of how to choose an optimal $$g$$ is a research area on its own, and depends largely on what the goal of the sampling is. +Some techniques even use an "adaptive" method where $$g$$ is "trained" on-the-fly using a learning algorithm! +Some of these methods and others are discussed in Ref. {{ "rosenthal2011optimal" | cite }} and Ref. {{ "gareth2001optimal" | cite }}. +In a lot of cases, people just use trial and error, as the algorithm is not too difficult to implement. + +After chosing $$g$$, we are almost ready to iterate. +We just need to choose the domain of $$x$$, and an initial point for $$ x_0 $$ ($$x_t$$ at $$t = 0$$) chosen randomly from the domain of $$x$$. + +{% method %} +{% sample lang="py" %} +[import:70-71, lang:"python"](code/python/metropolis.py) +{% endmethod %} + +### How to Iterate + +1. Generate new proposed position $$x' = x_t + g$$. +2. Calculate the acceptance probability, +$$ +A = \min\left(1, \frac{f(x')}{f(x_t)}\right). +$$ +3. Accept proposal, $$x'$$ with probability $$A$$. If your programming language doesn't have a built-in method for this, + * Generate a random number $$u$$ between $$0$$ and $$1$$. + * If $$ u \leq A $$, then __accept__ move, and set new position, $$x_{t+1} = x' $$. + * Otherwise, __reject__ move, and set new position to current position, $$x_{t+1} = x_t $$. +4. Increment $$t \rightarrow t + 1$$ and repeat from step 1. + +The code for steps 1 to 3 is: + +{% method %} +{% sample lang="py" %} +[import:34-42, lang:"python"](code/python/metropolis.py) +{% endmethod %} + +The following plot shows the result of running the algorithm for different numbers of iterations ($$N$$), with the same initial position. +The histograms are normalized so that they integrate to $$1$$. +We can see the convergence toward $$P(x)$$ as we increase $$N$$. + +

+ <FIG> multiple histograms +

+ + +## Example Code +The following code puts everything together, and runs the Metropolis algorithm for a number of steps given by `num_steps`. +All the positions visited by the algorithm are then written to a file, which can be later read and fed into a histogram or other density calculating scheme. +The code also incorporates a few tests of the algorithm using the `test_metropolis_iterate` method. +This test will create a normalized density histogram from the generated data, and compare it to $$P(x)$$ using the Root Mean Square Deviations metric {{ "rmsd_wiki" | cite }}. + +{% method %} +{% sample lang="py" %} +[import, lang:"python"](code/python/metropolis.py) +{% endmethod %} + + + + + +### Bibliography + +{% references %} {% endreferences %} + +## License + +##### Code Examples + +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). + + +##### Images/Graphics +- The animation "[Animated Random Walk](res/animated_random_walk.gif)" was created by [K. Shudipto Amin](https://github.com/shudipto-amin) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +- The animation "[Animated Metropolis](res/animated_metropolis.gif)" was created by [K. Shudipto Amin](https://github.com/shudipto-amin) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +- The image "[Plot of P(x)](res/plot_of_P.png)" was created by [K. Shudipto Amin](https://github.com/shudipto-amin) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +- The image "[Multiple Histograms](res/multiple_histograms.png)" was created by [K. Shudipto Amin](https://github.com/shudipto-amin) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +##### Text + +The text of this chapter was written by [K. Shudipto Amin](https://github.com/shudipto-amin) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +[

](https://creativecommons.org/licenses/by-sa/4.0/) + +##### Pull Requests + +After initial licensing ([#560](https://github.com/algorithm-archivists/algorithm-archive/pull/560)), the following pull requests have modified the text or graphics of this chapter: +- none diff --git a/contents/metropolis/res/1D_particles.png b/contents/metropolis/res/1D_particles.png new file mode 100644 index 0000000000000000000000000000000000000000..3d8ab7d99efb58e5368cd06942138a4f2135f08e GIT binary patch literal 23564 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 D5k^#o literal 0 HcmV?d00001 diff --git a/contents/metropolis/res/animated_metropolis.gif b/contents/metropolis/res/animated_metropolis.gif new file mode 100644 index 0000000000000000000000000000000000000000..93356bb7e0eb6eba096d5bb5a7e71fea4daa4d4e GIT binary patch literal 1647776 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

l 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