From cab35aae56f95d5d5f959b2085acc57dc217b525 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Tue, 15 Jun 2021 16:21:15 +0200 Subject: [PATCH 1/3] Add Rust implementation for The Barnsley Fern --- contents/barnsley/barnsley.md | 2 + contents/barnsley/code/rust/barnsley.rs | 101 ++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 contents/barnsley/code/rust/barnsley.rs diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index 4464e4523..3d7855f01 100644 --- a/contents/barnsley/barnsley.md +++ b/contents/barnsley/barnsley.md @@ -125,6 +125,8 @@ The biggest differences between the two code implementations is that the Barnsle {% method %} {% sample lang="jl" %} [import, lang:"julia"](code/julia/barnsley.jl) +{% sample lang="rs" %} +[import, lang:"rust"](code/rust/barnsley.rs) {% endmethod %} ### Bibliography diff --git a/contents/barnsley/code/rust/barnsley.rs b/contents/barnsley/code/rust/barnsley.rs new file mode 100644 index 000000000..ce9b61f20 --- /dev/null +++ b/contents/barnsley/code/rust/barnsley.rs @@ -0,0 +1,101 @@ +use rand::prelude::*; + +#[derive(Clone, Copy)] +struct Point2 { + x: f64, + y: f64, +} + +#[derive(Clone, Copy)] +struct Point3 { + x: f64, + y: f64, + z: f64, +} + +impl Point3 { + fn new(x: f64, y: f64, z: f64) -> Self { + Self { x, y, z } + } +} + +fn select_array(hutchinson_op: &[Vec], probabilities: &[f64]) -> Vec { + let mut rng = rand::thread_rng(); + let mut rnd = rng.gen::(); + + for (i, probability) in probabilities.iter().enumerate() { + if rnd < *probability { + return hutchinson_op[i].clone(); + } + rnd -= probability; + } + + return vec![]; +} + +fn chaos_game( + iters: usize, + initial_location: Point2, + hutchinson_op: &[Vec], + probabilities: &[f64], +) -> Vec { + let mut p = Point3 { + x: initial_location.x, + y: initial_location.y, + z: 1.0, + }; + (0..iters) + .into_iter() + .map(|_| { + let old_point = p; + let operation = select_array(hutchinson_op, probabilities); + p.x = operation[0].x * p.x + operation[0].y * p.y + operation[0].z * p.z; + p.y = operation[1].x * p.x + operation[1].y * p.y + operation[1].z * p.z; + p.z = operation[2].x * p.x + operation[2].y * p.y + operation[2].z * p.z; + Point2 { + x: old_point.x, + y: old_point.y, + } + }) + .collect() +} + +fn main() { + let barnsley_hutchinson = vec![ + vec![ + Point3::new(0.0, 0.0, 0.0), + Point3::new(0.0, 0.16, 0.0), + Point3::new(0.0, 0.0, 1.0), + ], + vec![ + Point3::new(0.85, 0.04, 0.0), + Point3::new(-0.04, 0.85, 1.60), + Point3::new(0.0, 0.0, 1.0), + ], + vec![ + Point3::new(0.20, -0.26, 0.0), + Point3::new(0.23, 0.22, 0.0), + Point3::new(0.0, 0.0, 1.0), + ], + vec![ + Point3::new(-0.15, 0.25, 0.0), + Point3::new(0.26, 0.24, 0.44), + Point3::new(0.0, 0.0, 1.0), + ], + ]; + + let barnsley_probabilities = vec![0.01, 0.85, 0.07, 0.07]; + + let mut out = String::new(); + + for point in chaos_game( + 10_000, + Point2 { x: 0.0, y: 0.0 }, + &barnsley_hutchinson, + &barnsley_probabilities, + ) { + out += format!("{}\t{}\n", point.x, point.y).as_str(); + } + + std::fs::write("./out.dat", out).unwrap(); +} From 43a32420b628521f73aadf697cc1eed535ddf5f5 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 23 Aug 2021 12:24:50 +0200 Subject: [PATCH 2/3] Change operators constants and add Cargo.toml --- contents/barnsley/barnsley.md | 2 +- contents/barnsley/code/rust/Cargo.toml | 9 +++++++++ contents/barnsley/code/rust/{barnsley.rs => src/main.rs} | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 contents/barnsley/code/rust/Cargo.toml rename contents/barnsley/code/rust/{barnsley.rs => src/main.rs} (96%) diff --git a/contents/barnsley/barnsley.md b/contents/barnsley/barnsley.md index 3d7855f01..ebcff30d3 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/barnsley.rs) +[import, lang:"rust"](code/rust/src/main.rs) {% endmethod %} ### Bibliography diff --git a/contents/barnsley/code/rust/Cargo.toml b/contents/barnsley/code/rust/Cargo.toml new file mode 100644 index 000000000..40780594a --- /dev/null +++ b/contents/barnsley/code/rust/Cargo.toml @@ -0,0 +1,9 @@ +[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.8.4" \ No newline at end of file diff --git a/contents/barnsley/code/rust/barnsley.rs b/contents/barnsley/code/rust/src/main.rs similarity index 96% rename from contents/barnsley/code/rust/barnsley.rs rename to contents/barnsley/code/rust/src/main.rs index ce9b61f20..23dfbabc2 100644 --- a/contents/barnsley/code/rust/barnsley.rs +++ b/contents/barnsley/code/rust/src/main.rs @@ -74,11 +74,11 @@ fn main() { ], vec![ Point3::new(0.20, -0.26, 0.0), - Point3::new(0.23, 0.22, 0.0), + Point3::new(0.23, 0.22, 1.60), Point3::new(0.0, 0.0, 1.0), ], vec![ - Point3::new(-0.15, 0.25, 0.0), + Point3::new(-0.15, 0.28, 0.0), Point3::new(0.26, 0.24, 0.44), Point3::new(0.0, 0.0, 1.0), ], From bd0cd8aaf2ba700dc828f1169c99de8e30731e36 Mon Sep 17 00:00:00 2001 From: Dimitri Belopopsky Date: Mon, 23 Aug 2021 13:04:29 +0200 Subject: [PATCH 3/3] Fix bug in matrix multiplication --- contents/barnsley/code/rust/src/main.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/contents/barnsley/code/rust/src/main.rs b/contents/barnsley/code/rust/src/main.rs index 23dfbabc2..6fee75375 100644 --- a/contents/barnsley/code/rust/src/main.rs +++ b/contents/barnsley/code/rust/src/main.rs @@ -1,5 +1,4 @@ use rand::prelude::*; - #[derive(Clone, Copy)] struct Point2 { x: f64, @@ -17,6 +16,13 @@ impl Point3 { fn new(x: f64, y: f64, z: f64) -> Self { Self { x, y, z } } + + fn matrix_mul(self, rhs: Vec) -> Self { + let x = rhs[0].x * self.x + rhs[0].y * self.y + rhs[0].z * self.z; + let y = rhs[1].x * self.x + rhs[1].y * self.y + rhs[1].z * self.z; + let z = rhs[2].x * self.x + rhs[2].y * self.y + rhs[2].z * self.z; + Self::new(x, y, z) + } } fn select_array(hutchinson_op: &[Vec], probabilities: &[f64]) -> Vec { @@ -39,7 +45,7 @@ fn chaos_game( hutchinson_op: &[Vec], probabilities: &[f64], ) -> Vec { - let mut p = Point3 { + let mut point = Point3 { x: initial_location.x, y: initial_location.y, z: 1.0, @@ -47,11 +53,9 @@ fn chaos_game( (0..iters) .into_iter() .map(|_| { - let old_point = p; + let old_point = point; let operation = select_array(hutchinson_op, probabilities); - p.x = operation[0].x * p.x + operation[0].y * p.y + operation[0].z * p.z; - p.y = operation[1].x * p.x + operation[1].y * p.y + operation[1].z * p.z; - p.z = operation[2].x * p.x + operation[2].y * p.y + operation[2].z * p.z; + point = point.matrix_mul(operation); Point2 { x: old_point.x, y: old_point.y,