{"id":17143825,"url":"https://github.com/asem000/stenciled","last_synced_at":"2025-08-24T06:07:09.300Z","repository":{"id":140101861,"uuid":"337583258","full_name":"ASEM000/stenciled","owner":"ASEM000","description":"Simplify  writing stencil kernels powered by  Numba","archived":false,"fork":false,"pushed_at":"2021-02-11T12:32:49.000Z","size":471,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-29T15:13:18.179Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ASEM000.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-02-10T01:18:53.000Z","updated_at":"2021-02-11T12:32:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"e5a49713-35bd-42c9-997f-9ecedc189576","html_url":"https://github.com/ASEM000/stenciled","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ASEM000%2Fstenciled","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ASEM000%2Fstenciled/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ASEM000%2Fstenciled/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ASEM000%2Fstenciled/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ASEM000","download_url":"https://codeload.github.com/ASEM000/stenciled/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245248008,"owners_count":20584460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-10-14T20:42:23.682Z","updated_at":"2025-03-24T09:42:35.791Z","avatar_url":"https://github.com/ASEM000.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **@stenciled**\n\n### Simplify  writing stencil kernels powered by  Numba\n\n#### Relative indexing\n\u003cimg src=\"https://i.imgur.com/me5bC17.png\" width=\"50%\" /\u003e\n\n#### Example 1 : 3x3 Mean \n```python\n# ---------------------------------- style 1 ----------------------------------\n@stenciled()\ndef mean(x):\n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n             x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n# ---------------------------------- style 2 ----------------------------------\n@stenciled(window=(3,3))\ndef mean(x): \n    return numpy.mean(x)   \n```\n\n\n#### Example 2 : Convolution ( with parallelization support)\n```python\n@stenciled(window=(3,3),relative_indexing=False,parallel=True)\ndef convolution_3x3(X,F):return numpy.sum(X*F)\n```\n\n#### Example 3 : Linear Diffusion\n\n\n\u003cimg src=\"https://i.imgur.com/kI69TUw.png\" width=\"500\" /\u003e\n\n```python\n@stenciled(inplace=True,window=(3,3),border='all')\ndef diffusion_1D(u,k): \n    return u[-1,0] + k * (u[-1,1] -2*u[-1,0] + u[-1,-1])\n```\n___\n## Speed Comparison\n\n#### Speed comparisons ( `@numba.stencil` vs `@stenciled` )\n\n```python\n#---------------------------------------------Test functions--------------------------------------------------------------\n@numba.stencil\ndef numba_full(x): \n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n            x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n@stenciled(window=(3,3))\ndef stenciled_short_hand(x) : return np.mean(x)\n\n@stenciled(window=(3,3),parallel=True)\ndef stenciled_short_hand_parallel(x) : return np.mean(x)\n\n@stenciled()\ndef stenciled_full(x): \n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n            x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n@stenciled(parallel=True)\ndef stenciled_full_parallel(x): \n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n            x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n@stenciled(window=(3,3))\ndef stenciled_full_window(x): \n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n            x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n@stenciled(parallel=True,window=(3,3))\ndef stenciled_full_window_parallel(x): \n    return ( x[1,-1] + x[1,0] + x[1,1] +\n             x[0,-1] + x[0,0] + x[0,1] +\n            x[-1,-1] +x[-1,0] + x[-1,1]) / 9\n\n```\n\n\n\u003cimg src='https://i.imgur.com/xUCtA4T.png' width='70%' /\u003e\n\n##### Observations\n- Specified window parameter has major speed improvements over non specified window size (kernel inference needs speed improvements )\n- `@stenciled` outperforms `@numba.stencil` for specified kernel size (window parameter)\n- Parallel versions outperforms single core versions for large arrays\n\n#### Example : Convolution in python vs parallel stenciled  vs single core stenciled\n\n```python\n#----------------------------------Parallel stenciled---------------------------------------------\n@stenciled(window=(3,3),parallel=True,relative_indexing=False)\ndef conv2dp(X,F):return np.sum(X*F)\n\n#----------------------------------single core stenciled---------------------------------------------\n@stenciled(window=(3,3),parallel=False,relative_indexing=False)\ndef conv2d(X,F):return np.sum(X*F)\n\n#----------------------------------Python --------------------------------------------\n#Credits : https://github.com/Alescontrela\ndef convolution_2D(image, filt, bias, s=1):\n    '''\n    Confolves `filt` over `image` using stride `s`\n        \n    '''\n    (n_f, n_c_f, f, _) = filt.shape # filter dimensions\n    n_c, in_dim, _ = image.shape # image dimensions\n    \n    out_dim = int((in_dim - f)/s)+1 # calculate output dimensions\n        \n    # ensure that the filter dimensions match the dimensions of the input image\n    assert n_c == n_c_f, \"Dimensions of filter must match dimensions of input image\"\n    \n    out = np.zeros((n_f,out_dim,out_dim)) # create the matrix to hold the values of the convolution operation\n    \n    # convolve each filter over the image\n    for curr_f in range(n_f):\n        curr_y = out_y = 0\n        # move filter vertically across the image\n        while curr_y + f \u003c= in_dim:\n            curr_x = out_x = 0\n            # move filter horizontally across the image \n            while curr_x + f \u003c= in_dim:\n                # perform the convolution operation and add the bias\n                out[curr_f, out_y, out_x] = np.sum(filt[curr_f] * image[:,curr_y:curr_y+f, curr_x:curr_x+f]) + bias[curr_f]\n                curr_x += s\n                out_x += 1\n            curr_y += s\n            out_y += 1\n        \n    return out\n\n```\n\n```python\nX = np.random.randint(low=0,high=1000,size=(500,500)).astype('float')*1000\nF = np.array([[3,4,4],[1,0,2],[-1,0,3]],dtype='float')\nB= np.array([[1]])\n\n%timeit conv2d(X,F)\n%timeit conv2dp(X,F)\n%timeit convolution_2D(X.reshape(1,500,500), F.reshape(1,1,3,3), B, s=1)\n_____________________________________________________________________________\n77.1 ms ± 2.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n35.4 ms ± 364 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n3.27 s ± 38.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n```\n**40x - 80x** speedup\n\n___\n\n## Comparison with @numba.stenciled\n\n|                                  | @numba.stencil  | @stenciled |\n|:--------------------------------:|:---------------:|:----------:|\n|        **Numba support**         |       ✔️        |     ✔️     |\n|    **Kenrel size inference**     |       ✔️        |     ✔️     |\n|      **Custom kernel size**      |       ❌        |     ✔️     |\n| **Multiple arrays as arguments** |       ✔️        |     ✔️     |\n|         **Update rules**         |       ❌        |     ✔️     |\n|       **Parallelization[1]**       |       ✔️        |     ✔️     |\n|       **Border Handeling**       | `constant` Only |     ✔️     |\n|     **N-Dimensional arrays**     |       ✔️        | `2D` only  |\n|  **Accepts external functions**  |       ❌        |    `✔️     |\n\n[1] For inplace = False case only\n___\n\n## Notebook examples\n\n```\n1) Basic operations\n    - Identity\n    - Mean filter\n    - Laplacian filter\n2) Border options\n    - Keep all borders\n    - Keep left border\n    - Keep Top border\n    - No borders  (default)\n3) Update options (inplace  updates)\n    - Linear convection\n    - Non linear convection\n    - 1D Diffusion\n4) Window options\n5) Using Functions \n    - Convolution\n    - Maxpool \n```\n\n**Credits : Mahmoud Asem - February 2021**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasem000%2Fstenciled","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasem000%2Fstenciled","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasem000%2Fstenciled/lists"}