{"id":21766360,"url":"https://github.com/drilonaliu/parallel-koch-snowflake","last_synced_at":"2026-05-07T09:32:18.981Z","repository":{"id":251752459,"uuid":"837235095","full_name":"drilonaliu/Parallel-Koch-Snowflake","owner":"drilonaliu","description":"GPU-accelerated Koch Snowflake generation with CUDA and OpenGL interoperability.","archived":false,"fork":false,"pushed_at":"2024-08-05T14:10:46.000Z","size":423,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-30T19:12:51.658Z","etag":null,"topics":["cuda","fractals","gpu","koch-snowflake","parallel-programming"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drilonaliu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-02T13:54:20.000Z","updated_at":"2024-10-10T22:15:11.000Z","dependencies_parsed_at":"2024-08-05T14:41:42.279Z","dependency_job_id":null,"html_url":"https://github.com/drilonaliu/Parallel-Koch-Snowflake","commit_stats":null,"previous_names":["drilonaliu/parallel-koch-snowflake"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/drilonaliu/Parallel-Koch-Snowflake","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drilonaliu%2FParallel-Koch-Snowflake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drilonaliu%2FParallel-Koch-Snowflake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drilonaliu%2FParallel-Koch-Snowflake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drilonaliu%2FParallel-Koch-Snowflake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drilonaliu","download_url":"https://codeload.github.com/drilonaliu/Parallel-Koch-Snowflake/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drilonaliu%2FParallel-Koch-Snowflake/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32731279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cuda","fractals","gpu","koch-snowflake","parallel-programming"],"created_at":"2024-11-26T13:16:57.205Z","updated_at":"2026-05-07T09:32:18.965Z","avatar_url":"https://github.com/drilonaliu.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Koch Snowflake\n\nThe Koch Snowflake is a classic example of a fractal, first described by the Swedish mathematician Helge von Koch in 1904. The fractal can be constructed starting from an equilateral triangle and then recursively altering each segment as follows:\n\n1. Divide the segment into three equal parts.\n2. Construct an equilateral triangle with the base being the middle segment obtained from the first step.\n3. Remove the middle segment that is the base of the triangle from the second step.\n\n   \nThe initial iterations of this fractal are shown below.\n\n\u003cdiv\u003e\n  \u003cp\u003e\n    \u003cimg src=\"images/koch_1.png\" width=\"200\" height=\"200\" alt=\"Tree 1\"\u003e\n    \u003cimg src=\"images/koch_2.png\" width=\"200\" height=\"200\" alt=\"Tree 2\"\u003e\n    \u003cimg src=\"images/koch_3.png\" width=\"200\" height=\"200\" alt=\"Tree 3\"\u003e\n    \u003cimg src=\"images/koch_4.png\" width=\"200\" height=\"200\" alt=\"Tree 4\"\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n## Construction of the equilateral triangle\n\nLet the points $A(x_1, y_1)$ and $B(x_2, y_2)$ be given. We need to find the points\n$C$, $D$, $E$ such that  $\\overrightarrow{AC}=\\frac{1}{2}\\overrightarrow{CB}$ ,\n$\\overrightarrow{DB}=\\frac{1}{2}\\overrightarrow{AD}$, so that $\\triangle CDE$ is equilateral.\n\n\u003cp\u003e\n   \u003cimg src=\"images/koch_5.png\"\u003e\n\u003c/p\u003e\n\n\nFrom the equation $\\overrightarrow{AC} = \\frac{1}{2}\\overrightarrow{CB}$,\nwe get\n\n$$\\left( c_1 - x_1, c_2 - y_1 \\right) = \\frac{1}{2} \\left( x_2 - c_1, y_2 - c_2 \\right)$$\n\n\nBy equating the corresponding coordinates of the ordered pairs on both sides of the equation, we obtain\n\n$$(c_1 - x_1) = \\frac{1}{2} (x_2 - c_1)$$\n$$(c_2 - y_1) = \\frac{1}{2} (y_2 - c_2)$$\n\nAnd we get the coordinates of the point C.\n\n$C = (c_1, c_2) = \\left( \\frac{x_2 - 2x_1}{3}, \\frac{y_2 - 2y_1}{3} \\right)$.\n\nIn an anologous way, we can find the coordinates of the point $D$.\n\n\nTriangle $\\triangle CDE$ is equilateral and consequently each angle of it is 60 deegres. It is sufficient to rotate the point $D$ around the point $C$\nfor 60 deegres to obtain the point $E$.\n\n$$e_1 = (d_1 - c_1) \\cos\\left(\\frac{\\pi}{3}\\right) - (d_2 - c_2) \\sin\\left(\\frac{\\pi}{3}\\right) + c_1$$\n\n$$e_2 = (d_1 - c_1) \\sin\\left(\\frac{\\pi}{3}\\right) + (d_2 - c_2) \\cos\\left(\\frac{\\pi}{3}\\right) + c_2$$\n\n\\\nIf the angle of rotation is $-60$  deegres, we will get the fractal known as Koch Anti-Snowflake.\n\n## Number of vertices\n\nLet $f(n)$  be the total number of vertices of the figure in iteration $n$.\nIn iteration 0 we have 3 points, and after each iteration in each segment three points are added.\n\n$$f(0) = 3$$\n\n$$f(1) = 3f(0) + f(0) = 4f(0) = 4 \\times 3$$\n\n$$f(2) = 3f(1) + f(1) = 4f(1) = 4^2 \\times 3$$\n\n$$f(3) = 3f(2) + f(2) = 4f(2) = 4^3 \\times 3$$\n\n$$\\vdots$$\n\n$$f(n) = 3 \\times 4^n$$\n\nWe use this sequence to tell OpenG how many points is going to connect as line segments, after we have calculated the coordinates of the points of the figure. \n\n```\nvoid renderSnowflakeFromBuffer() {\n     glColor3f(0.29f, 0.44f, 0.55f);\n     glPointSize(7.0f);\n     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);\n     glEnableVertexAttribArray(0);\n     numberOfPoints = 3*pow(4, iterations);\n     glDrawArrays(GL_LINE_LOOP, 0, numberOfPoints);\n}\n```\n\n## Parallelization\n\nParallelization occurs hierarchically, where a certain number of threads will be active in each iteration. Each active thread will take the \n$i$-th edge of the figure and find the three points for constructing the triangle on the segment. Each thread will then insert the four found segments into the array of all edges.\nThis array contains all the edges generated for each iteration, and its size is:\n\n$$h(n) = f(0) + f(1) + \\cdots + f(n-1) = \\sum_{i=0}^{n-1} f(i) = 3 \\sum_{i=0}^{n-1} 4^i = 4^n - 1$$\n\n\u003cp\u003e\n   \u003cimg src=\"images/koch_6.png\"\u003e\n\u003c/p\u003e\n\n\\\nFor each iteration there will be $3 \\times 4^n$ active threads. With the increase of\niterations, the number of active threads will rise exponentially:\n\n1.  Iteration 0: Only the thread with id 0 is active. This thread initializes the initial triangle.\n\n2.  Iteration 1: Threads 1-3 are active. Each thread takes the corresponding segment of the initial triangle and constructs an equileteral triangle on it.\n\n3.  Iteration 2: Threads 4-15 are active. These threads take the segments from the previous iteration and construct equilateral triangles on them.\n\n4.  Iteration n: Threads $4^{(n-1)}$ - $4^n$ are active. These threads take the segments from the previous iteration and construct equilateral triangles on them\n\n\n\nThis hierarchical approach ensures that each iteration fully utilizes the power of parallel processing. The figure below visualizes this thread process. \nThe dashed lines indicate that the threads are waiting for the next iteration to become active.\n\n\n\n## Kernel\n\nThe following kernel generates the fractal through parallel computation. Initially, the thread with index 0 handles the initializing triangle.\nFor each iteration, threads within the interval start_at to end_at are active and compute the necessary points to form the Koch curve. \nThe results are stored in the segment array, and the vertices are added to the points array for visualization. Synchronization ensures that all threads complete their tasks before proceeding to the next iteration.\n\n```\n    __global__ void kernel(float* points, Segment* segments, int start_iteration, int max_iteration , int inverted, int threadShiftIndex) {\n        Point A,B,C,A1,B1,C1;\n        Segment segment_1, segment_2, segment_3, segment_4;\n        \n        int idx = threadIdx.x + blockIdx.x * blockDim.x;\n        idx += threadShiftIndex;\n        \n        if (idx == 0) {\n        //CODE to handle the first iteration\n        }\n\n        auto g = cg::this_grid();\n        __syncthreads();\n\n        for (int iteration = start_iteration; iteration \u003c= max_iteration; iteration++){\n            int start_at = pow(4.0, iteration - 1);\n            int end_at = pow(4.0, iteration);\n            if (idx \u003e= start_at \u0026\u0026 idx \u003c end_at) {\n                  //Segment to built Koch curve on\n                Segment segment = segments[idx];\n                A = segment.A;\n                B = segment.B;\n                triangleOnSegment(A, B, \u0026A1, \u0026B1, \u0026C1, inverted);\n                //Koch curve\n                segment_1.A = A;\n                segment_1.B = B1;\n                segment_2.A = B1;\n                segment_2.B = C1;\n                segment_3.A = C1;\n                segment_3.B = A1;\n                segment_4.A = A1;\n                segment_4.B = B;\n                //Insert the generated koch curvers into segments array\n                int offset = end_at + 4 * (idx - start_at);\n                segments[offset] = segment_1;\n                segments[offset + 1] = segment_2;\n                segments[offset + 2] = segment_3;\n                segments[offset + 3] = segment_4;\n                //Insert vertices to points array\n                offset = 2 * 4 * (idx - start_at);\n                points[offset] = A.x;\n                points[offset + 1] = A.y;\n                points[offset + 2] = B1.x;\n                points[offset + 3] = B1.y;\n                points[offset + 4] = C1.x;\n                points[offset + 5] = C1.y;\n                points[offset + 6] = A1.x;\n                points[offset + 7] = A1.y;\n                points[offset + 8] = B.x;\n                points[offset + 9] = B.y;\n            }\n            g.sync();\n        }\n    }\n```\n\n## Comparisions\n\nTable below compares the excecution time in microseconds of the fractal between the sequential version and the parallel one. The CUDA implementation was done using cooperative groups, with 23,040 threads per kernel call. \n\n| Iteration | C++ (μs) | CUDA (μs) |\n|-----------|----------|-----------|\n| 0         | 2        | 23        |\n| 1         | 3        | 26        |\n| 2         | 16       | 41        |\n| 3         | 17       | 29        |\n| 4         | 50       | 37        |\n| 5         | 140      | 25        |\n| 6         | 787      | 27        |\n| 7         | 2514     | 60        |\n| 8         | 9101     | 93        |\n| 9         | 37411    | 409       |\n| 10        | 154053   | 1384      |\n| 11        | 607546   | 5032      |\n| 12        | 2240534  | 326359    |\n| 13        | 9075431  | 3123194   |\n\n\n\n\u003cp\u003e\n   \u003cimg src=\"images/koch_7.png\"\u003e\n\u003c/p\u003e\n\n\n\u003cp\u003e\n   \u003cimg src=\"images/koch_8.png\"\u003e\n\u003c/p\u003e\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrilonaliu%2Fparallel-koch-snowflake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrilonaliu%2Fparallel-koch-snowflake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrilonaliu%2Fparallel-koch-snowflake/lists"}