From 39dd28729910a5d449fcd6621859f5f7612ad73e Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Thu, 21 May 2020 00:07:42 -0400 Subject: [PATCH 1/6] Implement IFS in C++ --- contents/IFS/IFS.md | 4 +++ contents/IFS/code/c++/IFS.cpp | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 contents/IFS/code/c++/IFS.cpp diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index 87b1790d5..714616d73 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -128,6 +128,8 @@ Here, instead of tracking children of children, we track a single individual tha {% method %} {% sample lang="jl" %} [import:4-17, lang:"julia"](code/julia/IFS.jl) +{% sample lang="cpp" %} +[import:14-36, lang:"cpp"](code/c++/IFS.cpp) {% endmethod %} If we set the initial points to the on the equilateral triangle we saw before, we can see the Sierpinski triangle again after a few thousand iterations, as shown below: @@ -180,6 +182,8 @@ In addition, we have written the chaos game code to take in a set of points so t {% method %} {% sample lang="jl" %} [import, lang:"julia"](code/julia/IFS.jl) +{% sample lang="cpp" %} +[import, lang:"cpp"](code/c++/IFS.cpp) {% endmethod %} ### Bibliography diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/c++/IFS.cpp new file mode 100644 index 000000000..f00765574 --- /dev/null +++ b/contents/IFS/code/c++/IFS.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include + +struct Point { + double x, y; +}; + +Point operator+(Point lhs, Point rhs) { return {lhs.x + rhs.x, lhs.y + rhs.y}; } +Point operator*(double k, Point pt) { return {k * pt.x, k * pt.y}; } +Point operator*(Point pt, double k) { return k * pt; } + +template +std::vector chaosGame( + int numOutputPoints, + const std::vector& inputPoints, + RandEngine& engine) { + + // Choose first point randomly + std::uniform_real_distribution doubleDist(0.0, 1.0); + Point curPoint = {doubleDist(engine), doubleDist(engine)}; + + // Prepare local function to choose randomly from input points + std::uniform_int_distribution intDist(0, inputPoints.size() - 1); + auto randInputPoint = [&] { return inputPoints[intDist(engine)]; }; + + // For each output point, compute midpoint to random input point + std::vector outputPoints(numOutputPoints); + for (auto& outPoint : outputPoints) { + outPoint = curPoint; + curPoint = 0.5 * (curPoint + randInputPoint()); + } + + return outputPoints; +} + +int main() { + // Initialize pseudo-random engine with non-deterministic random seed + std::default_random_engine randEngine(std::random_device{}()); + + // 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. + std::vector inputPoints = { + {0.0, 0.0}, {0.5, std::sqrt(0.75)}, {1.0, 0.0}}; + auto outputPoints = chaosGame(10000, inputPoints, randEngine); + + // It will output the file sierpinski.dat, which can be plotted after + std::ofstream ofs("sierpinski.dat"); + for (auto pt : outputPoints) + ofs << pt.x << '\t' << pt.y << '\n'; +} From d2436a3cdbf3877eabc74e8ba2ef5396d374d691 Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Thu, 21 May 2020 00:33:16 -0400 Subject: [PATCH 2/6] Add my name to contributors --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index a9d53d836..96e4bcff6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -48,3 +48,4 @@ This file lists everyone, who contributed to this repo and wanted to show up her - dovisutu - Antetokounpo - Akash Dhiman +- Vincent Zalzal From f20b318924e9f7c41b45e4fcbd438a0137af35f4 Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Thu, 21 May 2020 21:30:08 -0400 Subject: [PATCH 3/6] Simpler version, no template --- contents/IFS/IFS.md | 2 +- contents/IFS/code/c++/IFS.cpp | 41 ++++++++++++++++++++--------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index 714616d73..fb702e55b 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -129,7 +129,7 @@ Here, instead of tracking children of children, we track a single individual tha {% sample lang="jl" %} [import:4-17, lang:"julia"](code/julia/IFS.jl) {% sample lang="cpp" %} -[import:14-36, lang:"cpp"](code/c++/IFS.cpp) +[import:32-44, lang:"cpp"](code/c++/IFS.cpp) {% endmethod %} If we set the initial points to the on the equilateral triangle we saw before, we can see the Sierpinski triangle again after a few thousand iterations, as shown below: diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/c++/IFS.cpp index f00765574..a38f2da9c 100644 --- a/contents/IFS/code/c++/IFS.cpp +++ b/contents/IFS/code/c++/IFS.cpp @@ -11,40 +11,45 @@ Point operator+(Point lhs, Point rhs) { return {lhs.x + rhs.x, lhs.y + rhs.y}; } Point operator*(double k, Point pt) { return {k * pt.x, k * pt.y}; } Point operator*(Point pt, double k) { return k * pt; } -template -std::vector chaosGame( - int numOutputPoints, - const std::vector& inputPoints, - RandEngine& engine) { +using PointVector = std::vector; - // Choose first point randomly - std::uniform_real_distribution doubleDist(0.0, 1.0); - Point curPoint = {doubleDist(engine), doubleDist(engine)}; +std::default_random_engine& rng() { + // Initialize static pseudo-random engine with non-deterministic random seed + static std::default_random_engine randEngine(std::random_device{}()); + return randEngine; +} + +double drand() { + return std::uniform_real_distribution(0.0, 1.0)(rng()); +} - // Prepare local function to choose randomly from input points - std::uniform_int_distribution intDist(0, inputPoints.size() - 1); - auto randInputPoint = [&] { return inputPoints[intDist(engine)]; }; +Point chooseRandPoint(const PointVector& points) { + auto index = + std::uniform_int_distribution(0, points.size() - 1)(rng()); + return points[index]; +} + +PointVector chaosGame(int numOutputPoints, const PointVector& inputPoints) { + // Choose first point randomly + Point curPoint = {drand(), drand()}; // For each output point, compute midpoint to random input point - std::vector outputPoints(numOutputPoints); + PointVector outputPoints(numOutputPoints); for (auto& outPoint : outputPoints) { outPoint = curPoint; - curPoint = 0.5 * (curPoint + randInputPoint()); + curPoint = 0.5 * (curPoint + chooseRandPoint(inputPoints)); } return outputPoints; } int main() { - // Initialize pseudo-random engine with non-deterministic random seed - std::default_random_engine randEngine(std::random_device{}()); - // 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. - std::vector inputPoints = { + PointVector inputPoints = { {0.0, 0.0}, {0.5, std::sqrt(0.75)}, {1.0, 0.0}}; - auto outputPoints = chaosGame(10000, inputPoints, randEngine); + auto outputPoints = chaosGame(10000, inputPoints); // It will output the file sierpinski.dat, which can be plotted after std::ofstream ofs("sierpinski.dat"); From 38bb6ee913e5b7721c9480045c547446cf2c73bf Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Thu, 21 May 2020 23:14:32 -0400 Subject: [PATCH 4/6] Separate rand function for int --- contents/IFS/IFS.md | 2 +- contents/IFS/code/c++/IFS.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index fb702e55b..d649e06d4 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -129,7 +129,7 @@ Here, instead of tracking children of children, we track a single individual tha {% sample lang="jl" %} [import:4-17, lang:"julia"](code/julia/IFS.jl) {% sample lang="cpp" %} -[import:32-44, lang:"cpp"](code/c++/IFS.cpp) +[import:34-46, lang:"cpp"](code/c++/IFS.cpp) {% endmethod %} If we set the initial points to the on the equilateral triangle we saw before, we can see the Sierpinski triangle again after a few thousand iterations, as shown below: diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/c++/IFS.cpp index a38f2da9c..a91c3551b 100644 --- a/contents/IFS/code/c++/IFS.cpp +++ b/contents/IFS/code/c++/IFS.cpp @@ -23,10 +23,12 @@ double drand() { return std::uniform_real_distribution(0.0, 1.0)(rng()); } -Point chooseRandPoint(const PointVector& points) { - auto index = - std::uniform_int_distribution(0, points.size() - 1)(rng()); - return points[index]; +std::size_t randrange(std::size_t numElems) { + return std::uniform_int_distribution(0, numElems - 1)(rng()); +} + +Point choose(const PointVector& points) { + return points[randrange(points.size())]; } PointVector chaosGame(int numOutputPoints, const PointVector& inputPoints) { @@ -37,7 +39,7 @@ PointVector chaosGame(int numOutputPoints, const PointVector& inputPoints) { PointVector outputPoints(numOutputPoints); for (auto& outPoint : outputPoints) { outPoint = curPoint; - curPoint = 0.5 * (curPoint + chooseRandPoint(inputPoints)); + curPoint = 0.5 * (curPoint + choose(inputPoints)); } return outputPoints; @@ -47,8 +49,7 @@ int main() { // 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. - PointVector inputPoints = { - {0.0, 0.0}, {0.5, std::sqrt(0.75)}, {1.0, 0.0}}; + PointVector inputPoints = {{0.0, 0.0}, {0.5, std::sqrt(0.75)}, {1.0, 0.0}}; auto outputPoints = chaosGame(10000, inputPoints); // It will output the file sierpinski.dat, which can be plotted after From 00bcb72d8500861084ccf2d821fa70e96113e422 Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Fri, 22 May 2020 07:57:43 -0400 Subject: [PATCH 5/6] Add comments --- contents/IFS/IFS.md | 2 +- contents/IFS/code/c++/IFS.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/contents/IFS/IFS.md b/contents/IFS/IFS.md index d649e06d4..b854153fa 100644 --- a/contents/IFS/IFS.md +++ b/contents/IFS/IFS.md @@ -129,7 +129,7 @@ Here, instead of tracking children of children, we track a single individual tha {% sample lang="jl" %} [import:4-17, lang:"julia"](code/julia/IFS.jl) {% sample lang="cpp" %} -[import:34-46, lang:"cpp"](code/c++/IFS.cpp) +[import:39-52, lang:"cpp"](code/c++/IFS.cpp) {% endmethod %} If we set the initial points to the on the equilateral triangle we saw before, we can see the Sierpinski triangle again after a few thousand iterations, as shown below: diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/c++/IFS.cpp index a91c3551b..dc265e76f 100644 --- a/contents/IFS/code/c++/IFS.cpp +++ b/contents/IFS/code/c++/IFS.cpp @@ -3,6 +3,7 @@ #include #include +// Simple X-Y point structure, along with some operators struct Point { double x, y; }; @@ -13,24 +14,29 @@ Point operator*(Point pt, double k) { return k * pt; } using PointVector = std::vector; +// Returns a pseudo-random number generator std::default_random_engine& rng() { // Initialize static pseudo-random engine with non-deterministic random seed static std::default_random_engine randEngine(std::random_device{}()); return randEngine; } +// Returns a random double in [0, 1) double drand() { return std::uniform_real_distribution(0.0, 1.0)(rng()); } +// Returns a random integer in [0, numElems-1) std::size_t randrange(std::size_t numElems) { return std::uniform_int_distribution(0, numElems - 1)(rng()); } +// Return a random point from the non-empty PointVector Point choose(const PointVector& points) { return points[randrange(points.size())]; } +// This is a function to simulate a "chaos game" PointVector chaosGame(int numOutputPoints, const PointVector& inputPoints) { // Choose first point randomly Point curPoint = {drand(), drand()}; From dc752ee124c7397a2f170e068099e8a91fe01d9f Mon Sep 17 00:00:00 2001 From: Vincent Zalzal Date: Fri, 22 May 2020 08:04:13 -0400 Subject: [PATCH 6/6] fix comment --- contents/IFS/code/c++/IFS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/IFS/code/c++/IFS.cpp b/contents/IFS/code/c++/IFS.cpp index dc265e76f..31d6ce946 100644 --- a/contents/IFS/code/c++/IFS.cpp +++ b/contents/IFS/code/c++/IFS.cpp @@ -26,7 +26,7 @@ double drand() { return std::uniform_real_distribution(0.0, 1.0)(rng()); } -// Returns a random integer in [0, numElems-1) +// Returns a random integer in [0, numElems-1] std::size_t randrange(std::size_t numElems) { return std::uniform_int_distribution(0, numElems - 1)(rng()); }