From e91b4c3bfbecb5ca6adc6bf573c580aecd4040b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 17 Jul 2026 20:15:49 +0200 Subject: [PATCH 1/5] disable rchk, yaml has issues --- .github/workflows/manual.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 5ed9b47..075effd 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -15,7 +15,7 @@ jobs: - 'clang-asan' - 'clang-ubsan' - 'gcc-asan' - - 'rchk' + # - 'rchk' yaml has issues as of 2026-07-17 - 'valgrind' env: From fc5d8a6ac6ada2501df821d6cda7ff4c24ed3bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 17 Jul 2026 20:16:21 +0200 Subject: [PATCH 2/5] fix integer overflow UB --- src/nn2poly_types.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nn2poly_types.h b/src/nn2poly_types.h index fd3d9d7..765f5c6 100644 --- a/src/nn2poly_types.h +++ b/src/nn2poly_types.h @@ -6,6 +6,7 @@ #include #include #include +#include using Term = std::vector; using Terms = std::vector; @@ -20,7 +21,8 @@ struct PartitionsList { struct TermHash { std::size_t operator()(Term const& key) const noexcept { std::size_t seed = key.size(); - for(auto x : key) { + for(auto item : key) { + uint32_t x = static_cast(item); x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; From ab6070e23bd7e049a826ab166c738624e1fddb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 17 Jul 2026 20:16:38 +0200 Subject: [PATCH 3/5] minor fixes --- src/linalg_arma.h | 6 +++--- src/linalg_eigen.h | 12 +++++------- src/linalg_torch.h | 11 +++++------ src/wrap.cpp | 6 +++--- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/linalg_arma.h b/src/linalg_arma.h index 9247d13..eb9ac50 100644 --- a/src/linalg_arma.h +++ b/src/linalg_arma.h @@ -23,9 +23,9 @@ inline Weights trans(const Weights& mat) { } inline Weights alg_linear(Weights& coeffs_list, const Weights& layer) { - arma::rowvec intercept = arma::zeros(coeffs_list.n_cols); - intercept[0] = 1.0; - return arma::trans(layer) * arma::join_cols(intercept, coeffs_list); + Weights mat = layer.rows(1, layer.n_rows - 1).t() * coeffs_list; + mat.col(0) += layer.row(0).t(); + return mat; } inline void add_partition(Weights& mat, int i, double scalar, const Vector& vec) { diff --git a/src/linalg_eigen.h b/src/linalg_eigen.h index 6d3ca39..1dd3559 100644 --- a/src/linalg_eigen.h +++ b/src/linalg_eigen.h @@ -11,11 +11,11 @@ inline int n_rows(const Weights& m) { return m.rows(); } inline int n_cols(const Weights& m) { return m.cols(); } inline Weights zeros(int rows, int cols) { - return Eigen::MatrixXd::Zero(rows, cols); + return Weights::Zero(rows, cols); } inline Vector zeros(int size) { - return Eigen::VectorXd::Zero(size); + return Vector::Zero(size); } inline Weights trans(const Weights& mat) { @@ -23,11 +23,9 @@ inline Weights trans(const Weights& mat) { } inline Weights alg_linear(const Weights& coeffs_list, const Weights& layer) { - Weights joined(coeffs_list.rows() + 1, coeffs_list.cols()); - joined.row(0).setZero(); - joined(0, 0) = 1.0; - joined.bottomRows(coeffs_list.rows()) = coeffs_list; - return layer.transpose() * joined; + Weights mat = layer.bottomRows(layer.rows() - 1).transpose() * coeffs_list; + mat.col(0) += layer.row(0).transpose(); + return mat; } inline void add_partition(Weights& mat, int i, double scalar, const Vector& vec) { diff --git a/src/linalg_torch.h b/src/linalg_torch.h index 4175a4e..40b6cac 100644 --- a/src/linalg_torch.h +++ b/src/linalg_torch.h @@ -25,10 +25,9 @@ inline Weights trans(const Weights& mat) { } inline Weights alg_linear(Weights& coeffs_list, const Weights& layer) { - auto intercept = torch::zeros({1, coeffs_list.size(1)}, coeffs_list.options()); - intercept[0][0] = 1.0; - auto joined = torch::cat({intercept, coeffs_list}, /*dim=*/0); - return torch::matmul(layer.t(), joined); + Weights mat = torch::matmul(layer.slice(0, 1, layer.size(0)).t(), coeffs_list); + mat.select(1, 0).add_(layer[0]); + return mat; } inline void add_partition(Weights& mat, int i, double scalar, const Vector& vec) { @@ -65,8 +64,8 @@ inline Vector accumulate_partition(const Weights& coeffs_input, int d, #include namespace Rcpp { -template <> torch::Tensor as(SEXP x); -NumericMatrix wrap(const torch::Tensor& data); +template <> nn2poly::linalg::Weights as(SEXP x); +NumericMatrix wrap(const nn2poly::linalg::Weights& data); } #endif diff --git a/src/wrap.cpp b/src/wrap.cpp index 3171dec..a0ce6a4 100644 --- a/src/wrap.cpp +++ b/src/wrap.cpp @@ -48,15 +48,15 @@ List wrap(const WeightsLists& data) { #ifdef TORCH_VERSION template <> -torch::Tensor as(SEXP x) { +Weights as(SEXP x) { NumericMatrix data(x); return torch::from_blob(const_cast(data.begin()), {data.nrow(), data.ncol()}, {1, data.nrow()}, torch::kFloat64 ).clone(); } -NumericMatrix wrap(const torch::Tensor& data) { - torch::Tensor cpu_t = data.to(torch::kCPU).to(torch::kFloat64).contiguous(); +NumericMatrix wrap(const Weights& data) { + Weights cpu_t = data.to(torch::kCPU).to(torch::kFloat64).contiguous(); int rows = cpu_t.size(0); int cols = cpu_t.size(1); NumericMatrix r_mat(rows, cols); From 06af3ee813bba67d70bbbbabcc52b8cb58be13b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 17 Jul 2026 20:17:49 +0200 Subject: [PATCH 4/5] remove gcc-asan, takes too much time --- .github/workflows/manual.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 075effd..a3e3051 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -14,7 +14,6 @@ jobs: container: - 'clang-asan' - 'clang-ubsan' - - 'gcc-asan' # - 'rchk' yaml has issues as of 2026-07-17 - 'valgrind' From a655bfb4b0795d2965b1a26deb83c4e8dc4a9dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1aki=20=C3=9Acar?= Date: Fri, 17 Jul 2026 20:20:05 +0200 Subject: [PATCH 5/5] bump version, update NEWS, cran-comments --- DESCRIPTION | 2 +- NEWS.md | 4 ++++ cran-comments.md | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b7e939b..5dd96da 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: nn2poly Title: Neural Network Weights Transformation into Polynomial Coefficients -Version: 1.0.0 +Version: 1.0.1 Authors@R: c( person(given = "Pablo", family = "Morala", role = c("aut", "cre"), email = "moralapablo@gmail.com", diff --git a/NEWS.md b/NEWS.md index fac757c..f09c8f4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# nn2poly 1.0.1 + +- Fix UB in hash implementation (#84). + # nn2poly 1.0.0 - Implement print method for nn2poly objects. diff --git a/cran-comments.md b/cran-comments.md index 1c0de7b..0d308cc 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,6 +1,6 @@ -## Release 1.0.0 +## Release 1.0.1 -- This release marks version 1.0.0 of the package. It includes the changes and improvements documented in NEWS.md, with significant performance improvements. +Fixes UB in hash implementation as reported in M1-SAN machine. ## Test environments