diff --git a/.github/workflows/deploy-jupyterlite.yml b/.github/workflows/deploy-jupyterlite.yml new file mode 100644 index 000000000..227ab1ea2 --- /dev/null +++ b/.github/workflows/deploy-jupyterlite.yml @@ -0,0 +1,64 @@ +name: Jupyterlite deployment + +on: + workflow_dispatch: + pull_request: + paths: + # Since we do not deploy in PRs and that this is only copying file from the repo + # the CI file is the only relevant change to watch for in CI on PRs + - .github/workflows/deploy-jupyterlite.yml + push: + branches: + - master + +permissions: + contents: read + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v6 + - uses: mamba-org/setup-micromamba@v3 + with: + cache-environment: true + post-cleanup: 'all' + environment-name: jupyterlite-builder + create-args: jupyter jupyterlite-core jupyterlite-xeus + - name: Build WASM environment + run: | + micromamba create -p ./wasm-env \ + --platform=emscripten-wasm32 \ + --channel https://prefix.dev/emscripten-forge-4x \ + --channel https://prefix.dev/conda-forge \ + xeus-cpp=0.10 + - name: Build Jupyterlite distribution + run: | + micromamba run -n jupyterlite-builder \ + jupyter lite build \ + --XeusAddon.prefix=./wasm-env \ + --contents include/ \ + --contents notebooks/ \ + --output-dir ./dist + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./dist + + deploy: + needs: build + if: github.ref == 'refs/heads/master' + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-24.04 + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/notebooks/simple.ipynb b/notebooks/simple.ipynb new file mode 100644 index 000000000..e40969542 --- /dev/null +++ b/notebooks/simple.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "2efd7be2-5ea7-42cb-a2e2-9ddb409bc893", + "metadata": {}, + "outputs": [], + "source": [ + "#include \n", + "#include \n", + "#include \n", + "#include \n", + "\n", + "#include " + ] + }, + { + "cell_type": "markdown", + "id": "6f498bff-4366-4e1c-ab25-3d3589740e78", + "metadata": {}, + "source": [ + "Comparing two implementation of element wise mean." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf6b2c85-1427-49a3-8bef-0340601319e8", + "metadata": {}, + "outputs": [], + "source": [ + "std::vector random_vector(std::size_t n)\n", + "{\n", + " static std::mt19937 gen(42);\n", + " std::uniform_real_distribution dist(0.0, 1.0);\n", + " std::vector v(n);\n", + " for (auto& x : v)\n", + " {\n", + " x = dist(gen);\n", + " }\n", + " return v;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2ab6177-60e2-4d65-b323-51a6a21ad530", + "metadata": {}, + "outputs": [], + "source": [ + "std::vector mean_scalar(const std::vector& a, const std::vector& b)\n", + "{\n", + " std::size_t size = a.size();\n", + " std::vector res(size);\n", + " for (std::size_t i = 0; i < size; ++i)\n", + " {\n", + " res[i] = (a[i] + b[i]) / 2;\n", + " }\n", + " return res;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "082ed2cd-273a-4c3c-a206-03b1efe49482", + "metadata": {}, + "outputs": [], + "source": [ + "std::vector mean_simd(const std::vector& a, const std::vector& b)\n", + "{\n", + " using b_type = xsimd::batch;\n", + " std::size_t inc = b_type::size;\n", + " std::size_t size = a.size();\n", + " std::vector res(size);\n", + "\n", + " // size for which the vectorization is possible\n", + " std::size_t vec_size = size - size % inc;\n", + " for (std::size_t i = 0; i < vec_size; i += inc)\n", + " {\n", + " b_type avec = b_type::load_unaligned(&a[i]);\n", + " b_type bvec = b_type::load_unaligned(&b[i]);\n", + " b_type rvec = (avec + bvec) / 2;\n", + " rvec.store_unaligned(&res[i]);\n", + " }\n", + " // Remaining part that cannot be vectorize\n", + " for (std::size_t i = vec_size; i < size; ++i)\n", + " {\n", + " res[i] = (a[i] + b[i]) / 2;\n", + " }\n", + " return res;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5959864d", + "metadata": {}, + "outputs": [], + "source": [ + "// Print v[begin:end] as grayscale ASCII blocks (dark = 0, light = 1).\n", + "void print_grayscale(const std::vector& v, std::size_t begin, std::size_t end)\n", + "{\n", + " for (std::size_t i = begin; i < end; ++i)\n", + " {\n", + " // map value in [0, 1] to a 24-bit truecolor gray (256 levels)\n", + " int gray = static_cast(v[i] * 255);\n", + " std::cout << \"\\033[38;2;\" << gray << \";\" << gray << \";\" << gray << \"m█\";\n", + " }\n", + " std::cout << \"\\033[0m\\n\";\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2068e201", + "metadata": {}, + "outputs": [], + "source": [ + "std::size_t n = 1000;\n", + "std::vector const a = random_vector(n);\n", + "std::vector const b = random_vector(n);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d5a7adc-5b55-4224-a4ca-5e438d1fc4d4", + "metadata": {}, + "outputs": [], + "source": [ + "auto const res_simd = mean_simd(a, b);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d279cd74-c397-4ea8-af15-3745f043f656", + "metadata": {}, + "outputs": [], + "source": [ + "auto const res_scalar = mean_scalar(a, b);" + ] + }, + { + "cell_type": "markdown", + "id": "a04ae145", + "metadata": {}, + "source": [ + "Each block is a value in `[0, 1]` shown as a grayscale shade (dark = low, light = high). The vector is drawn in chunks of 100, each chunk stacking input `a`, the SIMD mean, the scalar mean, and input `b`. The two mean rows should look identical, each sitting between its inputs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59ca84ad-8b97-4523-af0d-d3eca01b41d0", + "metadata": {}, + "outputs": [], + "source": [ + "std::size_t const width = 100;\n", + "for (std::size_t begin = 0; begin < n; begin += width)\n", + "{\n", + " std::size_t end = std::min(begin + width, n);\n", + " std::cout << \"a: \";\n", + " print_grayscale(a, begin, end);\n", + " std::cout << \"simd: \";\n", + " print_grayscale(res_simd, begin, end);\n", + " std::cout << \"scalar: \";\n", + " print_grayscale(res_scalar, begin, end);\n", + " std::cout << \"b: \";\n", + " print_grayscale(b, begin, end);\n", + " std::cout << \"\\n\";\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90b86fb4-0426-43fd-b5fc-8626ef8732a5", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "C++17", + "language": "cpp", + "name": "xcpp17" + }, + "language_info": { + "codemirror_mode": "text/x-c++src", + "file_extension": ".cpp", + "mimetype": "text/x-c++src", + "name": "C++", + "nbconvert_exporter": "", + "pygments_lexer": "", + "version": "cxx17" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}