From 6ad3e310d8d1814f403ab854d8f4df08d4c33934 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:17:12 +0100 Subject: [PATCH 01/12] Remove duplicate assertion --- test/exgboost_test.exs | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/exgboost_test.exs b/test/exgboost_test.exs index d6224df..9c3357a 100644 --- a/test/exgboost_test.exs +++ b/test/exgboost_test.exs @@ -219,9 +219,6 @@ defmodule EXGBoostTest do ) end) end - - refute is_nil(booster.best_iteration) - refute is_nil(booster.best_score) end test "eval with multiple metrics", context do From 87c989e0eb20623728267a0d36fdaad264855e4a Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:23:44 +0100 Subject: [PATCH 02/12] Deps upgrade --- mix.exs | 2 +- mix.lock | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mix.exs b/mix.exs index 2af10ac..b10780d 100644 --- a/mix.exs +++ b/mix.exs @@ -53,7 +53,7 @@ defmodule EXGBoost.MixProject do {:cc_precompiler, "~> 0.1.0", runtime: false}, {:exterval, "0.2.0"}, {:ex_json_schema, "~> 0.11.0"}, - {:httpoison, "~> 2.0", runtime: false}, + {:httpoison, "~> 3.0", runtime: false}, {:vega_lite, "~> 0.1"}, {:vega_lite_convert, "~> 1.0.1"}, {:kino, "~> 0.11"}, diff --git a/mix.lock b/mix.lock index 6953df7..0933dd9 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{ "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"}, - "certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"}, + "certifi": {:hex, :certifi, "2.17.0", "835748414307e15e05b17d0e518190228ce648b08d569a5cc93a85a40f3e5c9b", [:rebar3], [], "hexpm", "8122798a17f0293c80daada25d0f81c7f4d708c73fef782c7c9b1950e26e4d21"}, "complex": {:hex, :complex, "0.6.0", "b0130086a7a8c33574d293b2e0e250f4685580418eac52a5658a4bd148f3ccf1", [:mix], [], "hexpm", "0a5fa95580dcaf30fcd60fe1aaf24327c0fe401e98c24d892e172e79498269f9"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "dialyxir": {:hex, :dialyxir, "1.4.7", "dda948fcee52962e4b6c5b4b16b2d8fa7d50d8645bbae8b8685c3f9ecb7f5f4d", [:mix], [{:erlex, ">= 0.2.8", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b34527202e6eb8cee198efec110996c25c5898f43a4094df157f8d28f27d9efe"}, @@ -12,9 +12,10 @@ "ex_json_schema": {:hex, :ex_json_schema, "0.11.2", "8f8200e6afa5473f37dbebd1e72bf97d8d5dd0128125123ed1532611267f0138", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "395f4aaf32ea0a14d861b16695e7bc8a1b5d841e0fd374d25aef9701bf8da825"}, "exterval": {:hex, :exterval, "0.2.0", "cb2ce1dcaa08f7827d5eab25e0268e786b6b05b9b6d27f79d1d77f7b9f6dbd5d", [:mix], [], "hexpm", "30b48089fcc9a648d4bfcd17d51ab799b846c34db0fbf1fd6eb8a5526587510d"}, "fss": {:hex, :fss, "0.1.1", "9db2344dbbb5d555ce442ac7c2f82dd975b605b50d169314a20f08ed21e08642", [:mix], [], "hexpm", "78ad5955c7919c3764065b21144913df7515d52e228c09427a004afe9c1a16b0"}, - "hackney": {:hex, :hackney, "1.25.0", "390e9b83f31e5b325b9f43b76e1a785cbdb69b5b6cd4e079aa67835ded046867", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "7209bfd75fd1f42467211ff8f59ea74d6f2a9e81cbcee95a56711ee79fd6b1d4"}, - "httpoison": {:hex, :httpoison, "2.3.0", "10eef046405bc44ba77dc5b48957944df8952cc4966364b3cf6aa71dce6de587", [:mix], [{:hackney, "~> 1.21", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d388ee70be56d31a901e333dbcdab3682d356f651f93cf492ba9f06056436a2c"}, - "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "h2": {:hex, :h2, "0.10.2", "ea0146b9c8b5f3b5de16045765f5684db38ef1e66f1c60444890948cb1003e47", [:rebar3], [], "hexpm", "497a899f338b42e6a0b292524e635b0ce6f9379fa39395c8e38d06351cd9b9cf"}, + "hackney": {:hex, :hackney, "4.4.5", "a908f620525bb886a16613532324762e5166287f8c00c9888a762edee11a30c0", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.10.1", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 1.6.5", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.1", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "6d72bef4e135e94c522c271e11fbb6933efb0006ef235a3933807d0be73b71ec"}, + "httpoison": {:hex, :httpoison, "3.0.0", "8566a933bb9175236d1ec335978445b67cd1f5b5d3ead6ca4b80be469d41f5d9", [:mix], [{:hackney, "~> 4.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "9130197b7658901c493d6fcfb842fb9676300fa8a6c8ed058c8889cf1a77f3c2"}, + "idna": {:hex, :idna, "7.1.0", "1067a13043538129602d2f2ce6899d8713125c7d19734aa557ce2e3ea55bd4f1", [:rebar3], [], "hexpm", "6ae959a025bf36df61a8cab8508d9654891b5426a84c44d82deaffd6ddf8c71f"}, "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "kino": {:hex, :kino, "0.18.0", "a1ae60dcbd79413befea7902906be5c6a8f7380af86f86dbdc7994687ad3a13f", [:mix], [{:nx, "~> 0.1", [hex: :nx, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:table, "~> 0.1.2", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "11868c6d653523550ec208c7dc3717fffb68c0380e20fca395251d9db447d1a7"}, "kino_vega_lite": {:hex, :kino_vega_lite, "0.1.13", "03c00405987a2202e4b8014ee55eb7f5727691b3f13d76a3764f6eeccef45322", [:mix], [{:kino, "~> 0.7", [hex: :kino, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}, {:vega_lite, "~> 0.1.8", [hex: :vega_lite, repo: "hexpm", optional: false]}], "hexpm", "00c72bc270e7b9d3c339f726cdab0012fd3f2fc75e36c7548e0f250fe420fa10"}, @@ -22,12 +23,13 @@ "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.3", "4252d5d4098da7415c390e847c814bad3764c94a814a0b4245176215615e1035", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "953297c02582a33411ac6208f2c6e55f0e870df7f80da724ed613f10e6706afd"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"}, + "mimerl": {:hex, :mimerl, "1.5.0", "f35aca6f23242339b3666e0ac0702379e362b469d0aea167f6cc713547e777ed", [:rebar3], [], "hexpm", "db648ce065bae14ea84ca8b5dd123f42f49417cef693541110bf6f9e9be9ecc4"}, "nimble_csv": {:hex, :nimble_csv, "1.3.0", "b7f998dc62b222bce9596e46f028c7a5af04cb5dde6df2ea197c583227c54971", [:mix], [], "hexpm", "41ccdc18f7c8f8bb06e84164fc51635321e80d5a3b450761c4997d620925d619"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nx": {:hex, :nx, "0.11.0", "d37723dbd6cfa274a5def6d6664f5680c32e2eb8a1ce25ec6d91751967fa0abf", [:mix], [{:complex, "~> 0.6", [hex: :complex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "36157b21239aeb251d6cbac23eb0eb3495a5e1e0cbc2e6df16afd2ede1575205"}, - "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "parse_trans": {:hex, :parse_trans, "3.4.2", "c352ddc1a0d5e54f9b1654d45f9c432eef76f9cea371c55ddff769ef688fdb74", [:rebar3], [], "hexpm", "4c25347de3b7c35732d32e69ab43d1ceee0beae3f3b3ade1b59cbd3dd224d9ca"}, + "quic": {:hex, :quic, "1.6.5", "28b7d49c1732b2de3861701bb03ae7798537240552370ac49f0d139d2ea8f621", [:rebar3], [], "hexpm", "de1a88972c33201a50d1a17c8c4a14528bd1d8f25ef705897d680ae312d0aa78"}, "rustler_precompiled": {:hex, :rustler_precompiled, "0.8.4", "700a878312acfac79fb6c572bb8b57f5aae05fe1cf70d34b5974850bbf2c05bf", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "3b33d99b540b15f142ba47944f7a163a25069f6d608783c321029bc1ffb09514"}, "scidata": {:hex, :scidata, "0.1.11", "fe3358bac7d740374b4f2a7eff6a1cb02e5ee7f87f7cdb1e8648ad93c533165f", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.1", [hex: :nimble_csv, repo: "hexpm", optional: false]}, {:stb_image, "~> 0.4", [hex: :stb_image, repo: "hexpm", optional: true]}], "hexpm", "90873337a9d5fe880d640517efa93d3c07e46c8ba436de44117f581800549f93"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, @@ -36,4 +38,5 @@ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"}, "vega_lite": {:hex, :vega_lite, "0.1.11", "2b261d21618f6fa9f63bb4542f0262982d2e40aea3f83e935788fe172902b3c2", [:mix], [{:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: false]}], "hexpm", "d18c3f11369c14bdf36ab53010c06bf5505c221cbcb32faac7420cf6926b3c50"}, "vega_lite_convert": {:hex, :vega_lite_convert, "1.0.1", "1cc0309998c10bce9d944ae631938a433e9cad4ccf7344f9a192d9ddcab1bd93", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.4", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}, {:vega_lite, ">= 0.0.0", [hex: :vega_lite, repo: "hexpm", optional: false]}], "hexpm", "1e12b4ef3943510d3597e4876a10c6ab333b8ee71204b5e571605d80aa3cbd76"}, + "webtransport": {:hex, :webtransport, "0.4.1", "60ef6cd99282b5964c8172d674519239e31e357d934bde028bec70da34636fe5", [:rebar3], [{:h2, "~> 0.10.1", [hex: :h2, repo: "hexpm", optional: false]}, {:quic, "~> 1.6.5", [hex: :quic, repo: "hexpm", optional: false]}], "hexpm", "006e4e52a8f03b69201d4637c85b424a4ddccc1909f32c5742fed8d495a75174"}, } From e92e57a17316457eba80a8a069dc10190e9f4a36 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:24:22 +0100 Subject: [PATCH 03/12] Implement devcontainer for more isolated builds --- .devcontainer/Dockerfile | 46 ++++++++++++++++++++++++++++ .devcontainer/devcontainer-lock.json | 24 +++++++++++++++ .devcontainer/devcontainer.json | 33 ++++++++++++++++++++ .gitignore | 1 - 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer-lock.json create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..ed08691 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,46 @@ +FROM hexpm/elixir:1.20.2-erlang-29.0.2-debian-trixie-20260623-slim + +ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 +ENV CC=gcc-14 +ENV CXX=g++-14 + +RUN apt-get update && \ + apt-get dist-upgrade --yes && \ + apt-get install --yes --no-install-recommends \ + build-essential \ + ca-certificates \ + cmake \ + curl \ + g++-14 \ + gcc-14 \ + git \ + inotify-tools \ + ninja-build \ + openssh-client \ + pkg-config \ + python3 \ + python3-venv \ + sudo \ + zsh && \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 140 && \ + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 140 && \ + update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 140 && \ + update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-14 140 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +RUN useradd -m -s /bin/zsh -u 1000 -G sudo dev && \ + echo 'dev ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/dev && \ + chmod 0440 /etc/sudoers.d/dev && \ + mkdir -p /workspace && \ + chown dev:dev /workspace + +USER dev + +RUN git config --global --add safe.directory /workspace && \ + mix local.hex --force && \ + mix local.rebar --force + +WORKDIR /workspace diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..523de18 --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,24 @@ +{ + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "version": "2.5.9", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a", + "integrity": "sha256:cb0c4d3c276f157eed17935747e364178d75fee17f55c4e129966f64633deb3a" + }, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "version": "1.10.0", + "resolved": "ghcr.io/devcontainers/features/docker-outside-of-docker@sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e", + "integrity": "sha256:c2c2cf829505ead8e4892c88c31b6594ae94a2bbb209e16e1fac456c1a3a624e" + }, + "ghcr.io/devcontainers/features/git:1": { + "version": "1.3.7", + "resolved": "ghcr.io/devcontainers/features/git@sha256:a3e43ff91b9f5f6bd2c14bd510d43e5e698f1266dc41027ba4e04e7e45be607a", + "integrity": "sha256:a3e43ff91b9f5f6bd2c14bd510d43e5e698f1266dc41027ba4e04e7e45be607a" + }, + "ghcr.io/devcontainers/features/github-cli:1": { + "version": "1.1.0", + "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671", + "integrity": "sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..c452d66 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,33 @@ +{ + "name": "EXGBoost Erlang 29 GCC 14", + "build": { + "dockerfile": "Dockerfile", + "context": ".." + }, + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "workspaceFolder": "/workspace", + "containerEnv": { + "CC": "gcc-14", + "CXX": "g++-14", + "MIX_ENV": "dev" + }, + "customizations": { + "vscode": { + "extensions": [ + "jakebecker.elixir-ls" + ] + } + }, + "postCreateCommand": "mix deps.get", + "remoteUser": "dev", + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true + }, + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "moby": false + } + } +} diff --git a/.gitignore b/.gitignore index 15fd0cd..839a055 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ erl_crash.dump *.beam /config/*.secret.exs .elixir_ls/ -.tool-versions .vscode/ checksum.exs .DS_Store \ No newline at end of file From 41aca8c44423e106fc962a5fad14682c39013938 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:24:50 +0100 Subject: [PATCH 04/12] Update GH workflows --- .github/workflows/ci.yml | 20 +++++++++++++++++--- .github/workflows/precompile.yml | 18 +++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3353236..cea239a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,15 +10,29 @@ jobs: test: name: Test OTP ${{ matrix.otp }} / Elixir ${{ matrix.elixir }} runs-on: ubuntu-24.04 + env: + CC: gcc-14 + CXX: g++-14 + MIX_ENV: test strategy: fail-fast: false matrix: - otp: ["28.3"] - elixir: ["1.18.4", "1.19.5"] + include: + - otp: "28.3" + elixir: "1.18.4" + - otp: "28.3" + elixir: "1.19.5" + - otp: "29.0.2" + elixir: "1.20.2" steps: - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y build-essential cmake ninja-build gcc-14 g++-14 + - uses: erlef/setup-beam@v1 with: otp-version: ${{ matrix.otp }} @@ -36,4 +50,4 @@ jobs: run: mix format --check-formatted - name: Run tests - run: MIX_ENV=test mix test \ No newline at end of file + run: MIX_ENV=test mix test diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml index cee049a..8107003 100644 --- a/.github/workflows/precompile.yml +++ b/.github/workflows/precompile.yml @@ -10,12 +10,19 @@ jobs: runs-on: ubuntu-24.04 env: MIX_ENV: "prod" + CC: gcc-14 + CXX: g++-14 strategy: matrix: - otp: ["28.3"] - elixir: ["1.18.4", "1.19.5"] + include: + - otp: "28.3" + elixir: "1.18.4" + - otp: "28.3" + elixir: "1.19.5" + - otp: "29.0.2" + elixir: "1.20.2" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: erlef/setup-beam@v1 with: otp-version: ${{matrix.otp}} @@ -24,10 +31,11 @@ jobs: run: | mix local.hex --force mix local.rebar --force - - name: Install system dependecies + - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y build-essential automake autoconf pkg-config bc m4 unzip zip \ + cmake ninja-build gcc-14 g++-14 \ gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \ gcc-riscv64-linux-gnu g++-riscv64-linux-gnu - name: Mix Test @@ -59,7 +67,7 @@ jobs: otp: ["27.0", "28.0"] elixir: ["1.18.4"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: asdf-vm/actions/install@v2 with: tool_versions: | From e1e086b4676b41c352a744c92c9e37091540cb6f Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:25:06 +0100 Subject: [PATCH 05/12] Point to my github repo --- mix.exs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mix.exs b/mix.exs index b10780d..8623000 100644 --- a/mix.exs +++ b/mix.exs @@ -8,27 +8,27 @@ defmodule EXGBoost.MixProject do version: @version, make_precompiler: {:nif, CCPrecompiler}, make_precompiler_url: - "https://github.com/acalejos/exgboost/releases/download/v#{@version}/@{artefact_filename}", + "https://github.com/iperks/exgboost/releases/download/v#{@version}/@{artefact_filename}", make_precompiler_priv_paths: ["libexgboost.*", "lib"], # NIF Versions correspond to OTP Releases # https://github.com/erlang/otp/blob/d3aa6c044c3927f011fb76ac087d5ce0e814954c/erts/emulator/beam/erl_nif.h#L57 make_precompiler_nif_versions: [ - versions: ["2.15", "2.16", "2.17"] + versions: ["2.15", "2.16", "2.17", "2.18"] ], elixir: "~> 1.17", start_permanent: Mix.env() == :prod, compilers: [:elixir_make] ++ Mix.compilers(), deps: deps(), name: "EXGBoost", - source_url: "https://github.com/acalejos/exgboost", - homepage_url: "https://github.com/acalejos/exgboost", + source_url: "https://github.com/iperks/exgboost", + homepage_url: "https://github.com/iperks/exgboost", docs: docs(), package: package(), before_closing_body_tag: &before_closing_body_tag/1, name: "EXGBoost", description: "Elixir bindings for the XGBoost library. `EXGBoost` provides an implementation of XGBoost that works with - [Nx](https://hexdocs.pm/nx/Nx.html) tensors." + [Nx](https://hexdocs.pm/nx/Nx.html) tensors. Maintained fork of acalejos/exgboost." ] end @@ -65,9 +65,9 @@ defmodule EXGBoost.MixProject do defp package do [ - maintainers: ["Andres Alejos"], + maintainers: ["Ian Perks"], licenses: ["Apache-2.0"], - links: %{"GitHub" => "https://github.com/acalejos/exgboost"}, + links: %{"GitHub" => "https://github.com/iperks/exgboost"}, files: [ "lib", "mix.exs", From d2d37791dea6e819b2e36a04862dbe45fe795394 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:25:23 +0100 Subject: [PATCH 06/12] Fix minor issues in makefile --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 217cc67..2fd89e0 100644 --- a/Makefile +++ b/Makefile @@ -54,13 +54,13 @@ else endif $(EXGBOOST_SO): $(EXGBOOST_CACHE_SO) - @ mkdir -p $(PRIV_DIR) + @mkdir -p $(PRIV_DIR) cp -a $(abspath $(EXGBOOST_CACHE_LIB_DIR)) $(EXGBOOST_LIB_DIR) ; \ cp -a $(abspath $(EXGBOOST_CACHE_SO)) $(EXGBOOST_SO) ; $(EXGBOOST_CACHE_SO): $(XGBOOST_LIB_DIR_FLAG) $(C_SRCS) @mkdir -p cache - cp -a $(XGBOOST_LIB_DIR) $(EXGBOOST_CACHE_LIB_DIR) + cp -R $(XGBOOST_LIB_DIR) $(EXGBOOST_CACHE_LIB_DIR) cp $(XGBOOST_DIR)/lib/$(LIBXGBOOST) $(EXGBOOST_CACHE_LIB_DIR) $(CC) $(CFLAGS) $(wildcard $(EXGBOOST_DIR)/src/*.c) $(LDFLAGS) -o $(EXGBOOST_CACHE_SO) $(POST_INSTALL) @@ -68,7 +68,7 @@ $(EXGBOOST_CACHE_SO): $(XGBOOST_LIB_DIR_FLAG) $(C_SRCS) # This new target handles fetching the source code. # It only runs if the .git directory inside the source folder is missing. $(XGBOOST_DIR)/.git: - mkdir -p $(XGBOOST_DIR) && \ + @mkdir -p $(XGBOOST_DIR) && \ cd $(XGBOOST_DIR) && \ git init && \ git remote add origin $(XGBOOST_GIT_REPO) && \ From 5b36911223ead6194c55d839d186862cfbb215e3 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:25:39 +0100 Subject: [PATCH 07/12] Fix for stricter C++ compile warnings --- c/exgboost/src/booster.c | 52 ++++++++++++++++++++++------------------ c/exgboost/src/config.c | 6 ++--- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/c/exgboost/src/booster.c b/c/exgboost/src/booster.c index 6833115..b0a23a2 100644 --- a/c/exgboost/src/booster.c +++ b/c/exgboost/src/booster.c @@ -300,7 +300,7 @@ ERL_NIF_TERM EXGBoosterEvalOneIter(ErlNifEnv *env, int argc, int iter = -1; unsigned num_dmats = 0; unsigned num_evnames = 0; - char *out = NULL; + const char *out = NULL; ERL_NIF_TERM ret = -1; int result = -1; if (4 != argc) { @@ -329,7 +329,7 @@ ERL_NIF_TERM EXGBoosterEvalOneIter(ErlNifEnv *env, int argc, ret = exg_error(env, "dmats and evnames must have the same length"); goto END; } - result = XGBoosterEvalOneIter(booster, iter, dmats, evnames, + result = XGBoosterEvalOneIter(booster, iter, dmats, (const char **)evnames, (bst_ulong)num_dmats, &out); if (result == 0) { ret = exg_ok(env, enif_make_string(env, out, ERL_NIF_LATIN1)); @@ -348,7 +348,7 @@ ERL_NIF_TERM EXGBoosterGetAttr(ErlNifEnv *env, int argc, BoosterHandle booster; BoosterHandle **booster_resource = NULL; char *key = NULL; - char *out = NULL; + const char *out = NULL; ERL_NIF_TERM ret = -1; int result = -1; int success = -1; @@ -444,7 +444,7 @@ ERL_NIF_TERM EXGBoosterGetAttrNames(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { BoosterHandle booster; BoosterHandle **booster_resource = NULL; - char **out = NULL; + const char **out = NULL; bst_ulong out_len = 0; ERL_NIF_TERM ret = -1; int result = -1; @@ -504,7 +504,8 @@ ERL_NIF_TERM EXGBoosterSetStrFeatureInfo(ErlNifEnv *env, int argc, goto END; } handle = *resource; - result = XGBoosterSetStrFeatureInfo(handle, field, features, num_features); + result = XGBoosterSetStrFeatureInfo(handle, field, (const char **)features, + num_features); if (result == 0) { ret = ok_atom(env); } else { @@ -572,10 +573,10 @@ ERL_NIF_TERM EXGBoosterFeatureScore(ErlNifEnv *env, int argc, BoosterHandle **booster_resource = NULL; char *config = NULL; bst_ulong out_n_features = 0; - char **out_features = NULL; + const char **out_features = NULL; bst_ulong out_dim = 0; - bst_ulong *out_shape = NULL; - float *out_scores = NULL; + const bst_ulong *out_shape = NULL; + const float *out_scores = NULL; ERL_NIF_TERM ret = -1; int result = -1; if (2 != argc) { @@ -622,9 +623,9 @@ ERL_NIF_TERM EXGBoosterFeatureScore(ErlNifEnv *env, int argc, } static ERL_NIF_TERM collect_prediction_results(ErlNifEnv *env, - bst_ulong *out_shape, + const bst_ulong *out_shape, bst_ulong out_dim, - float *out_result) { + const float *out_result) { bst_ulong out_len = 1; ERL_NIF_TERM shape_arr[out_dim]; for (bst_ulong j = 0; j < out_dim; ++j) { @@ -649,9 +650,9 @@ ERL_NIF_TERM EXGBoosterPredictFromDMatrix(ErlNifEnv *env, int argc, DMatrixHandle dmatrix; DMatrixHandle **dmatrix_resource = NULL; char *config = NULL; - bst_ulong *out_shape = NULL; + const bst_ulong *out_shape = NULL; bst_ulong out_dim = 0; - float *out_result = NULL; + const float *out_result = NULL; ERL_NIF_TERM ret = -1; int result = -1; @@ -697,9 +698,9 @@ ERL_NIF_TERM EXGBoosterPredictFromDense(ErlNifEnv *env, int argc, DMatrixHandle **proxy_resource = NULL; char *values = NULL; char *config = NULL; - bst_ulong *out_shape = NULL; + const bst_ulong *out_shape = NULL; bst_ulong out_dim = 0; - float *out_result = NULL; + const float *out_result = NULL; int result = -1; ERL_NIF_TERM ret = -1; if (4 != argc) { @@ -752,10 +753,10 @@ ERL_NIF_TERM EXGBoosterPredictFromCSR(ErlNifEnv *env, int argc, char *indices = NULL; char *data = NULL; char *config = NULL; - bst_ulong ncols = 0; - bst_ulong *out_shape = NULL; + int ncols = 0; + const bst_ulong *out_shape = NULL; bst_ulong out_dim = 0; - float *out_result = NULL; + const float *out_result = NULL; int result = -1; ERL_NIF_TERM ret = -1; if (7 != argc) { @@ -783,6 +784,10 @@ ERL_NIF_TERM EXGBoosterPredictFromCSR(ErlNifEnv *env, int argc, ret = exg_error(env, "Ncols must be an integer"); goto END; } + if (ncols < 0) { + ret = exg_error(env, "Ncols must be non-negative"); + goto END; + } if (!exg_get_string(env, argv[5], &config)) { ret = exg_error(env, "Config must be a JSON-encoded string"); goto END; @@ -795,8 +800,9 @@ ERL_NIF_TERM EXGBoosterPredictFromCSR(ErlNifEnv *env, int argc, } booster = *booster_resource; result = - XGBoosterPredictFromCSR(booster, indptr, indices, data, ncols, config, - proxy, &out_shape, &out_dim, &out_result); + XGBoosterPredictFromCSR(booster, indptr, indices, data, + (bst_ulong)ncols, config, proxy, &out_shape, + &out_dim, &out_result); if (result == 0) { ret = collect_prediction_results(env, out_shape, out_dim, out_result); } else { @@ -890,7 +896,7 @@ ERL_NIF_TERM EXGBoosterSerializeToBuffer(ErlNifEnv *env, int argc, BoosterHandle booster; BoosterHandle **booster_resource = NULL; bst_ulong out_len = 0; - char *out_buf = NULL; + const char *out_buf = NULL; int result = -1; ERL_NIF_TERM ret = -1; ErlNifBinary out_bin; @@ -995,7 +1001,7 @@ ERL_NIF_TERM EXGBoosterSaveModelToBuffer(ErlNifEnv *env, int argc, BoosterHandle booster; BoosterHandle **booster_resource = NULL; bst_ulong out_len = 0; - char *out_buf = NULL; + const char *out_buf = NULL; char *config = NULL; int result = -1; ERL_NIF_TERM ret = -1; @@ -1038,7 +1044,7 @@ ERL_NIF_TERM EXGBoosterSaveJsonConfig(ErlNifEnv *env, int argc, BoosterHandle booster; BoosterHandle **booster_resource = NULL; bst_ulong out_len = 0; - char *out_buf = NULL; + const char *out_buf = NULL; int result = -1; ERL_NIF_TERM ret = -1; ErlNifBinary out_bin; @@ -1109,7 +1115,7 @@ ERL_NIF_TERM EXGBoosterDumpModelEx(ErlNifEnv *env, int argc, BoosterHandle booster; BoosterHandle **booster_resource = NULL; bst_ulong out_len = 0; - char **out_dump_array = NULL; + const char **out_dump_array = NULL; char *fmap = NULL; int with_stats = 0; char *format = NULL; diff --git a/c/exgboost/src/config.c b/c/exgboost/src/config.c index 89f432e..9590d66 100644 --- a/c/exgboost/src/config.c +++ b/c/exgboost/src/config.c @@ -59,7 +59,7 @@ ERL_NIF_TERM EXGBSetGlobalConfig(ErlNifEnv *env, int argc, ERL_NIF_TERM EXGBGetGlobalConfig(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { - char *out = NULL; + const char *out = NULL; int result = -1; ERL_NIF_TERM ret = 0; if (argc != 0) { @@ -68,7 +68,7 @@ ERL_NIF_TERM EXGBGetGlobalConfig(ErlNifEnv *env, int argc, } // No need to free out, it's a pointer to a static string defined in the // xgboost config struct - result = XGBGetGlobalConfig((char const **)&out); + result = XGBGetGlobalConfig(&out); if (result == 0) { ret = exg_ok(env, enif_make_string(env, out, ERL_NIF_LATIN1)); } else { @@ -76,4 +76,4 @@ ERL_NIF_TERM EXGBGetGlobalConfig(ErlNifEnv *env, int argc, } END: return ret; -} \ No newline at end of file +} From 874c66310bae0c84ef9e5f6454a07617ef0cbe9c Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:25:48 +0100 Subject: [PATCH 08/12] Bump to 0.7.0 --- mix.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mix.exs b/mix.exs index 8623000..1dbd2b4 100644 --- a/mix.exs +++ b/mix.exs @@ -1,6 +1,6 @@ defmodule EXGBoost.MixProject do use Mix.Project - @version "0.6.1" + @version "0.7.0" def project do [ From 79184212d86fdd0f6334c33b9be87b69aceb4f72 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:28:47 +0100 Subject: [PATCH 09/12] Setup and install asdf runner in osx --- .github/workflows/precompile.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml index 8107003..837a91b 100644 --- a/.github/workflows/precompile.yml +++ b/.github/workflows/precompile.yml @@ -68,7 +68,8 @@ jobs: elixir: ["1.18.4"] steps: - uses: actions/checkout@v4 - - uses: asdf-vm/actions/install@v2 + - uses: asdf-vm/actions/setup@v3 + - uses: asdf-vm/actions/install@v3 with: tool_versions: | erlang ${{matrix.otp}} From d95880e9205e8fd3d8e67ee715164535d7363853 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:48:32 +0100 Subject: [PATCH 10/12] Prevent nodejs warnings --- .github/workflows/ci.yml | 2 +- .github/workflows/precompile.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cea239a..1c0bf8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: elixir: "1.20.2" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install system dependencies run: | diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml index 837a91b..0dd75d5 100644 --- a/.github/workflows/precompile.yml +++ b/.github/workflows/precompile.yml @@ -22,7 +22,7 @@ jobs: - otp: "29.0.2" elixir: "1.20.2" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: erlef/setup-beam@v1 with: otp-version: ${{matrix.otp}} @@ -67,7 +67,7 @@ jobs: otp: ["27.0", "28.0"] elixir: ["1.18.4"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: asdf-vm/actions/setup@v3 - uses: asdf-vm/actions/install@v3 with: From ff098eb36390f1c9d4fc1d9fc3e78215b2a054a2 Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:50:59 +0100 Subject: [PATCH 11/12] Use beam setup rather than asdf --- .github/workflows/precompile.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml index 0dd75d5..8c8ae45 100644 --- a/.github/workflows/precompile.yml +++ b/.github/workflows/precompile.yml @@ -55,10 +55,7 @@ jobs: macos: runs-on: ${{matrix.runner}} - # Homebrew supports versioned Erlang/OTP but not Elixir - # It's a deliberate design decision from Homebrew to - # only support versioned distributions for certain packages - name: Mac (ARM) Erlang/OTP ${{matrix.otp}} / Elixir + name: Mac (ARM) Erlang/OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} env: MIX_ENV: "prod" strategy: @@ -68,12 +65,10 @@ jobs: elixir: ["1.18.4"] steps: - uses: actions/checkout@v5 - - uses: asdf-vm/actions/setup@v3 - - uses: asdf-vm/actions/install@v3 + - uses: erlef/setup-beam@v1 with: - tool_versions: | - erlang ${{matrix.otp}} - elixir ${{matrix.elixir}} + otp-version: ${{matrix.otp}} + elixir-version: ${{matrix.elixir}} - name: Install libomp run: | brew install libomp From daa5b1b4ff89ac1a2309acda7f8a79ece31cfcba Mon Sep 17 00:00:00 2001 From: Ian Perks Date: Wed, 1 Jul 2026 13:59:43 +0100 Subject: [PATCH 12/12] Update precompile matrix for macos --- .github/workflows/precompile.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/precompile.yml b/.github/workflows/precompile.yml index 8c8ae45..1494c92 100644 --- a/.github/workflows/precompile.yml +++ b/.github/workflows/precompile.yml @@ -54,21 +54,16 @@ jobs: cache/*.tar.gz macos: - runs-on: ${{matrix.runner}} - name: Mac (ARM) Erlang/OTP ${{matrix.otp}} / Elixir ${{matrix.elixir}} + runs-on: macos-15 + name: Mac (ARM) Erlang/OTP 29.0.2 / Elixir 1.20.2 env: MIX_ENV: "prod" - strategy: - matrix: - runner: ["macos-15"] - otp: ["27.0", "28.0"] - elixir: ["1.18.4"] steps: - uses: actions/checkout@v5 - uses: erlef/setup-beam@v1 with: - otp-version: ${{matrix.otp}} - elixir-version: ${{matrix.elixir}} + otp-version: "29.0.2" + elixir-version: "1.20.2" - name: Install libomp run: | brew install libomp