From dfe54200cc70a5952a2c3062ba980eaa641be07a Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 01/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/DMI.cpp diff --git a/src/DMI.cpp b/src/DMI.cpp new file mode 100644 index 0000000..e69de29 From 5963bfbe2bf70a18434180aa61d1f03e796fef01 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 02/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/src/DMI.cpp b/src/DMI.cpp index e69de29..4aaeb2c 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "pc.h" + +// Wrapper function to perform delayed mutual information analysis +// [[Rcpp::export(rng = false)]] +Rcpp::NumericVector RcppDMI( + const Rcpp::NumericVector& target, + const Rcpp::NumericVector& rt, + const Rcpp::NumericVector& eps, + const Rcpp::IntegerVector& lib, + const Rcpp::IntegerVector& pred, + const Rcpp::IntegerVector& E, + int tau = 1, + int style = 0, + const std::string& dist_metric = "euclidean", + int k = 3, + int threads = 1, + int parallel_level = 0, + Rcpp::Nullable nb = R_NilValue, + Rcpp::Nullable nrows = R_NilValue) +{ + // --- Input Conversion and Validation --- + std::vector tg = Rcpp::as>(target); + const size_t n_obs = tg.size(); + + // Convert library indices (R 1-based → C++ 0-based) + std::vector lib_std = Rcpp::as>(lib); + for (auto& idx : lib_std) + { + if (idx < 1 || idx > n_obs) + { + Rcpp::stop("lib index %d out of bounds [1, %d]", + static_cast(idx), + static_cast(n_obs)); + } + idx -= 1; + } + + // Convert prediction indices (R 1-based → C++ 0-based) + std::vector pred_std = Rcpp::as>(pred); + for (auto& idx : pred_std) + { + if (idx < 1 || idx > n_obs) + { + Rcpp::stop("pred index %d out of bounds [1, %d]", + static_cast(idx), + static_cast(n_obs)); + } + idx -= 1; + } + + // Construct embedding dimension E + std::vector E_std = Rcpp::as>(E); + for (auto& singleE : E_std) + { + if (singleE < 0) singleE = std::abs(singleE); + } + size_t max_E = static_cast(*std::max_element(E_std.begin(), E_std.end())); + if (max_E < 2) max_E = 2; + + // Convert rt and eps + std::vector rt_vec = Rcpp::as>(rt); + std::vector eps_vec = Rcpp::as>(eps); + + // Expand rt and eps + std::vector rt_std(max_E); + std::vector eps_std(max_E); + + // ---- rt ---- + if (rt_vec.size() == 1) + { + std::fill(rt_std.begin(), rt_std.end(), rt_vec[0]); + } + else + { + size_t src_len = rt_vec.size(); + for (size_t i = 0; i < rt_std.size(); ++i) + { + rt_std[i] = rt_vec[i % src_len]; + } + } + + // ---- eps ---- + if (eps_vec.size() == 1) + { + std::fill(eps_std.begin(), eps_std.end(), eps_vec[0]); + } + else + { + size_t src_len = eps_vec.size(); + for (size_t i = 0; i < eps_std.size(); ++i) { + eps_std[i] = eps_vec[i % src_len]; + } + } + + // --- Embedding Construction --- + std::vector> Mx; + + if (nb.isNotNull()) + { + // Convert Rcpp::List to std::vector> + std::vector> nb_std = pc::convert::nb2std(nb.get()); + Mx = pc::embed::embed( + tg, nb_std, max_E, + static_cast(std::abs(tau)), + static_cast(std::abs(style))); + } + else if (nrows.isNotNull()) + { + size_t n_rows = static_cast(std::abs(Rcpp::as(nrows))); + + std::vector> tm = + pc::embed::gridVec2Mat(tg, n_rows); + Mx = pc::embed::embed( + tm, max_E, + static_cast(std::abs(tau)), + static_cast(std::abs(style))); + } + else + { + Mx = pc::embed::embed( + tg, max_E, + static_cast(std::abs(tau)), + static_cast(std::abs(style))); + + size_t max_lag = (tau == 0) + ? (max_E - 1) + : ((max_E - 1) * static_cast(std::abs(tau))); + + lib_std.erase( + std::remove_if(lib_std.begin(), lib_std.end(), + [&](size_t idx){ return idx + 1 < max_lag; }), + lib_std.end() + ); + + pred_std.erase( + std::remove_if(pred_std.begin(), pred_std.end(), + [&](size_t idx){ return idx + 1 < max_lag; }), + pred_std.end() + ); + } + + // ---- sort + unique lib/pred ---- + std::sort(lib_std.begin(), lib_std.end()); + lib_std.erase( + std::unique(lib_std.begin(), lib_std.end()), + lib_std.end() + ); + + std::sort(pred_std.begin(), pred_std.end()); + pred_std.erase( + std::unique(pred_std.begin(), pred_std.end()), + pred_std.end() + ); + + // ---- filter lib/pred (remove NaN in target/source) ---- + size_t write = 0; + for (size_t i = 0; i < lib_std.size(); ++i) + { + size_t idx = lib_std[i]; + if (!std::isnan(tg[idx])) + { + lib_std[write++] = idx; + } + } + lib_std.resize(write); + + write = 0; + for (size_t i = 0; i < pred_std.size(); ++i) + { + size_t idx = pred_std[i]; + if (!std::isnan(tg[idx])) + { + pred_std[write++] = idx; + } + } + pred_std.resize(write); + + // --- Prepare for data slicing --- + std::vector selected_indices; + selected_indices.reserve(lib_std.size() + pred_std.size()); + for (size_t i = 0; i < lib_std.size(); ++i) + selected_indices.push_back(lib_std[i]); + for (size_t i = 0; i < pred_std.size(); ++i) + selected_indices.push_back(pred_std[i]); + std::sort(selected_indices.begin(), selected_indices.end()); + selected_indices.erase( + std::unique(selected_indices.begin(), selected_indices.end()), + selected_indices.end() + ); + + // --- Check if full set is used --- + bool use_subset = (selected_indices.size() < Mx.size()); + + // --- Perform Pattern Causality Analysis --- + std::vector res; + + if (!use_subset) + { + // --- Full data: no slicing needed --- + res = pc::fnn::fnn( + Mx, lib_std, pred_std, rt_std, eps_std, dist_metric, + static_cast(std::abs(k)), + static_cast(std::abs(threads)), + static_cast(std::abs(parallel_level))); + } + else + { + // --- Slice Mx --- + std::vector> Mx_sub; + Mx_sub.reserve(selected_indices.size()); + + for (size_t i = 0; i < selected_indices.size(); ++i) + { + size_t idx = selected_indices[i]; + Mx_sub.push_back(Mx[idx]); + } + + // --- Subset mode: build index map --- + std::unordered_map index_map; + index_map.reserve(selected_indices.size()); + + for (size_t i = 0; i < selected_indices.size(); ++i) + { + index_map[selected_indices[i]] = i; + } + + // --- Remap lib indices --- + for (size_t i = 0; i < lib_std.size(); ++i) + { + lib_std[i] = index_map[lib_std[i]]; + } + + // --- Remap pred indices --- + for (size_t i = 0; i < pred_std.size(); ++i) + { + pred_std[i] = index_map[pred_std[i]]; + } + + // --- Run patcaus on subset --- + res = pc::fnn::fnn( + Mx_sub, lib_std, pred_std, rt_std, eps_std, dist_metric, + static_cast(std::abs(k)), + static_cast(std::abs(threads)), + static_cast(std::abs(parallel_level))); + } + + // Convert the result back to Rcpp::NumericVector and set names as "E:1", "E:2", ..., "E:n" + Rcpp::NumericVector result = Rcpp::wrap(res); + Rcpp::CharacterVector resnames(result.size()); + for (int i = 0; i < result.size(); ++i) { + resnames[i] = "E:" + std::to_string(i + 1); + } + result.names() = resnames; + + // Terminal-friendly hint (one-time, non-intrusive) + Rcpp::Rcout << "[fnn] Input E values exceeding max embeddable dimension were truncated, and values < 2 were clamped to 2.\n" + << "[fnn] Max embedding dimension E_max is auto-computed, with results returned for dimensions 1 through E_max.\n" + << "[fnn] Output 'E:i' (where i = 1 to E_max-1) corresponds to the comparison between dimension i and i+1.\n"; + + return result; +} From 6f90c21535a37a5dac99a2d1b1234c2d7247a70a Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 03/21] draft cpp header for dmi --- inst/include/pc/dmi.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inst/include/pc/dmi.hpp b/inst/include/pc/dmi.hpp index 1b614f6..f5b65a9 100644 --- a/inst/include/pc/dmi.hpp +++ b/inst/include/pc/dmi.hpp @@ -48,8 +48,8 @@ namespace dmi * * Parameters: * vec - Input numeric vector representing the ordered series - * pred - Indices defining the sample positions (from past to present) * tau - Vector of lag steps (non-negative integers) + * pred - Indices defining the sample positions (from past to present) * k - Number of nearest neighbors for KSG estimator (default: 3) * alg - Algorithm variant for KSG estimator (default: 0) * base - Logarithm base for mutual information (default: 2.0) @@ -63,8 +63,8 @@ namespace dmi */ inline std::vector dmi( const std::vector& vec, - const std::vector& pred, const std::vector& tau, + const std::vector& pred, size_t k = 3, size_t alg = 0, double base = 2.0, From 8aed4b9e4c1ea6de9603940fb85c7b1f95e70d64 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 04/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 4aaeb2c..e0f1445 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -12,19 +12,13 @@ // [[Rcpp::export(rng = false)]] Rcpp::NumericVector RcppDMI( const Rcpp::NumericVector& target, - const Rcpp::NumericVector& rt, - const Rcpp::NumericVector& eps, - const Rcpp::IntegerVector& lib, + const Rcpp::NumericVector& tau, const Rcpp::IntegerVector& pred, - const Rcpp::IntegerVector& E, - int tau = 1, - int style = 0, - const std::string& dist_metric = "euclidean", int k = 3, - int threads = 1, - int parallel_level = 0, - Rcpp::Nullable nb = R_NilValue, - Rcpp::Nullable nrows = R_NilValue) + int alg = 0, + double base = 2.0, + bool normalize = false, + int threads = 1) { // --- Input Conversion and Validation --- std::vector tg = Rcpp::as>(target); From 989981b57955d3c02e874178d88982cb62aa65ef Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 05/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index e0f1445..701c87d 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -24,18 +24,7 @@ Rcpp::NumericVector RcppDMI( std::vector tg = Rcpp::as>(target); const size_t n_obs = tg.size(); - // Convert library indices (R 1-based → C++ 0-based) - std::vector lib_std = Rcpp::as>(lib); - for (auto& idx : lib_std) - { - if (idx < 1 || idx > n_obs) - { - Rcpp::stop("lib index %d out of bounds [1, %d]", - static_cast(idx), - static_cast(n_obs)); - } - idx -= 1; - } + std::vector tau_std = Rcpp::as>(tau); // Convert prediction indices (R 1-based → C++ 0-based) std::vector pred_std = Rcpp::as>(pred); From 782f665e663cf6569d74d454474d500e91bcaf3a Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 06/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 88 +++++++---------------------------------------------- 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 701c87d..8116c0a 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -48,72 +48,14 @@ Rcpp::NumericVector RcppDMI( size_t max_E = static_cast(*std::max_element(E_std.begin(), E_std.end())); if (max_E < 2) max_E = 2; - // Convert rt and eps - std::vector rt_vec = Rcpp::as>(rt); - std::vector eps_vec = Rcpp::as>(eps); - - // Expand rt and eps - std::vector rt_std(max_E); - std::vector eps_std(max_E); - - // ---- rt ---- - if (rt_vec.size() == 1) - { - std::fill(rt_std.begin(), rt_std.end(), rt_vec[0]); - } - else - { - size_t src_len = rt_vec.size(); - for (size_t i = 0; i < rt_std.size(); ++i) - { - rt_std[i] = rt_vec[i % src_len]; - } - } - - // ---- eps ---- - if (eps_vec.size() == 1) - { - std::fill(eps_std.begin(), eps_std.end(), eps_vec[0]); - } - else - { - size_t src_len = eps_vec.size(); - for (size_t i = 0; i < eps_std.size(); ++i) { - eps_std[i] = eps_vec[i % src_len]; - } - } - - // --- Embedding Construction --- - std::vector> Mx; - - if (nb.isNotNull()) - { - // Convert Rcpp::List to std::vector> - std::vector> nb_std = pc::convert::nb2std(nb.get()); - Mx = pc::embed::embed( - tg, nb_std, max_E, - static_cast(std::abs(tau)), - static_cast(std::abs(style))); - } - else if (nrows.isNotNull()) - { - size_t n_rows = static_cast(std::abs(Rcpp::as(nrows))); - - std::vector> tm = - pc::embed::gridVec2Mat(tg, n_rows); - Mx = pc::embed::embed( - tm, max_E, - static_cast(std::abs(tau)), - static_cast(std::abs(style))); - } - else - { - Mx = pc::embed::embed( - tg, max_E, - static_cast(std::abs(tau)), - static_cast(std::abs(style))); + // ---- sort + unique lib/pred ---- + std::sort(lib_std.begin(), lib_std.end()); + lib_std.erase( + std::unique(lib_std.begin(), lib_std.end()), + lib_std.end() + ); - size_t max_lag = (tau == 0) + size_t max_lag = (tau == 0) ? (max_E - 1) : ((max_E - 1) * static_cast(std::abs(tau))); @@ -123,18 +65,10 @@ Rcpp::NumericVector RcppDMI( lib_std.end() ); - pred_std.erase( - std::remove_if(pred_std.begin(), pred_std.end(), - [&](size_t idx){ return idx + 1 < max_lag; }), - pred_std.end() - ); - } - - // ---- sort + unique lib/pred ---- - std::sort(lib_std.begin(), lib_std.end()); - lib_std.erase( - std::unique(lib_std.begin(), lib_std.end()), - lib_std.end() + pred_std.erase( + std::remove_if(pred_std.begin(), pred_std.end(), + [&](size_t idx){ return idx + 1 < max_lag; }), + pred_std.end() ); std::sort(pred_std.begin(), pred_std.end()); From cca34620d9c3ed1fd2ecc4ebea77bff5db78bc70 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 07/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 8116c0a..99abdd3 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -24,8 +24,6 @@ Rcpp::NumericVector RcppDMI( std::vector tg = Rcpp::as>(target); const size_t n_obs = tg.size(); - std::vector tau_std = Rcpp::as>(tau); - // Convert prediction indices (R 1-based → C++ 0-based) std::vector pred_std = Rcpp::as>(pred); for (auto& idx : pred_std) @@ -39,16 +37,11 @@ Rcpp::NumericVector RcppDMI( idx -= 1; } - // Construct embedding dimension E - std::vector E_std = Rcpp::as>(E); - for (auto& singleE : E_std) - { - if (singleE < 0) singleE = std::abs(singleE); - } - size_t max_E = static_cast(*std::max_element(E_std.begin(), E_std.end())); - if (max_E < 2) max_E = 2; + // Construct time delay step tau + std::vector tau_std = Rcpp::as>(tau); + size_t max_tau = static_cast(*std::max_element(tau_std.begin(), tau_std.end())); - // ---- sort + unique lib/pred ---- + // ---- sort predict indices ---- std::sort(lib_std.begin(), lib_std.end()); lib_std.erase( std::unique(lib_std.begin(), lib_std.end()), From 533d9ebc6a815f7467ece775833ac0a5b87096e5 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 08/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 99abdd3..dd94d0e 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -42,25 +42,13 @@ Rcpp::NumericVector RcppDMI( size_t max_tau = static_cast(*std::max_element(tau_std.begin(), tau_std.end())); // ---- sort predict indices ---- - std::sort(lib_std.begin(), lib_std.end()); - lib_std.erase( - std::unique(lib_std.begin(), lib_std.end()), - lib_std.end() - ); - size_t max_lag = (tau == 0) ? (max_E - 1) : ((max_E - 1) * static_cast(std::abs(tau))); - lib_std.erase( - std::remove_if(lib_std.begin(), lib_std.end(), - [&](size_t idx){ return idx + 1 < max_lag; }), - lib_std.end() - ); - pred_std.erase( std::remove_if(pred_std.begin(), pred_std.end(), - [&](size_t idx){ return idx + 1 < max_lag; }), + [&](size_t idx){ return idx + 1 < max_tau; }), pred_std.end() ); From 3edd5e4e0b975686d2bf25172b46ead1728db070 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 09/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index dd94d0e..24eecba 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -58,18 +58,7 @@ Rcpp::NumericVector RcppDMI( pred_std.end() ); - // ---- filter lib/pred (remove NaN in target/source) ---- - size_t write = 0; - for (size_t i = 0; i < lib_std.size(); ++i) - { - size_t idx = lib_std[i]; - if (!std::isnan(tg[idx])) - { - lib_std[write++] = idx; - } - } - lib_std.resize(write); - + // ---- filter pred (remove NaN in target/source) ---- write = 0; for (size_t i = 0; i < pred_std.size(); ++i) { From 29ad808cf177f25339146decc855d94871eeabb9 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 10/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 24eecba..0ae99d9 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -70,14 +70,14 @@ Rcpp::NumericVector RcppDMI( } pred_std.resize(write); - // --- Prepare for data slicing --- - std::vector selected_indices; + t> selected_indices; selected_indices.reserve(lib_std.size() + pred_std.size()); for (size_t i = 0; i < lib_std.size(); ++i) selected_indices.push_back(lib_std[i]); for (size_t i = 0; i < pred_std.size(); ++i) selected_indices.push_back(pred_std[i]); - std::sort(selected_indices.begin(), selected_indices.end()); + std::sort(selected_i// --- Prepare for data slicing --- + std::vector res; + // --- Perform Delay Mutual Information Analysis --- + std::vector res = pc::dmi::dmi( + tg, tau_std, pred_std, + static_cast(std::abs(k)), + static_cast(std::abs(alg)), + base, normalize, + static_cast(std::abs(threads))); if (!use_subset) { @@ -132,11 +137,7 @@ Rcpp::NumericVector RcppDMI( } // --- Run patcaus on subset --- - res = pc::fnn::fnn( - Mx_sub, lib_std, pred_std, rt_std, eps_std, dist_metric, - static_cast(std::abs(k)), - static_cast(std::abs(threads)), - static_cast(std::abs(parallel_level))); + } // Convert the result back to Rcpp::NumericVector and set names as "E:1", "E:2", ..., "E:n" From 3656318734ed7f3a9dc0d8a8d57817549ed0b2b4 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 11/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 62 ----------------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 0ae99d9..a90b73a 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -69,22 +69,6 @@ Rcpp::NumericVector RcppDMI( } } pred_std.resize(write); - - t> selected_indices; - selected_indices.reserve(lib_std.size() + pred_std.size()); - for (size_t i = 0; i < lib_std.size(); ++i) - selected_indices.push_back(lib_std[i]); - for (size_t i = 0; i < pred_std.size(); ++i) - selected_indices.push_back(pred_std[i]); - std::sort(selected_i// --- Prepare for data slicing --- - std::vector res = pc::dmi::dmi( @@ -94,52 +78,6 @@ Rcpp::NumericVector RcppDMI( base, normalize, static_cast(std::abs(threads))); - if (!use_subset) - { - // --- Full data: no slicing needed --- - res = pc::fnn::fnn( - Mx, lib_std, pred_std, rt_std, eps_std, dist_metric, - static_cast(std::abs(k)), - static_cast(std::abs(threads)), - static_cast(std::abs(parallel_level))); - } - else - { - // --- Slice Mx --- - std::vector> Mx_sub; - Mx_sub.reserve(selected_indices.size()); - - for (size_t i = 0; i < selected_indices.size(); ++i) - { - size_t idx = selected_indices[i]; - Mx_sub.push_back(Mx[idx]); - } - - // --- Subset mode: build index map --- - std::unordered_map index_map; - index_map.reserve(selected_indices.size()); - - for (size_t i = 0; i < selected_indices.size(); ++i) - { - index_map[selected_indices[i]] = i; - } - - // --- Remap lib indices --- - for (size_t i = 0; i < lib_std.size(); ++i) - { - lib_std[i] = index_map[lib_std[i]]; - } - - // --- Remap pred indices --- - for (size_t i = 0; i < pred_std.size(); ++i) - { - pred_std[i] = index_map[pred_std[i]]; - } - - // --- Run patcaus on subset --- - - } - // Convert the result back to Rcpp::NumericVector and set names as "E:1", "E:2", ..., "E:n" Rcpp::NumericVector result = Rcpp::wrap(res); Rcpp::CharacterVector resnames(result.size()); From e1533d80f7e1ceb559af5024ea8fa3f8476f4a2a Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 12/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index a90b73a..eb1ec28 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -78,18 +78,18 @@ Rcpp::NumericVector RcppDMI( base, normalize, static_cast(std::abs(threads))); - // Convert the result back to Rcpp::NumericVector and set names as "E:1", "E:2", ..., "E:n" + // Convert the result back to Rcpp::NumericVector and set names as "tau:1", "tau:2", ..., "tau:n" Rcpp::NumericVector result = Rcpp::wrap(res); Rcpp::CharacterVector resnames(result.size()); for (int i = 0; i < result.size(); ++i) { - resnames[i] = "E:" + std::to_string(i + 1); + resnames[i] = "tau:" + std::to_string(i + 1); } result.names() = resnames; // Terminal-friendly hint (one-time, non-intrusive) - Rcpp::Rcout << "[fnn] Input E values exceeding max embeddable dimension were truncated, and values < 2 were clamped to 2.\n" + Rcpp::Rcout << "[fnn] Input tau E values exceeding max embeddable dimension were truncated, and values < 2 were clamped to 2.\n" << "[fnn] Max embedding dimension E_max is auto-computed, with results returned for dimensions 1 through E_max.\n" - << "[fnn] Output 'E:i' (where i = 1 to E_max-1) corresponds to the comparison between dimension i and i+1.\n"; + << "[fnn] Output 'tau:i' (where i = 1 to E_max-1) corresponds to the comparison between dimension i and i+1.\n"; return result; } From 49065795567edcae8039950a78a1721c911b9d41 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 13/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index eb1ec28..151f74f 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -42,10 +42,6 @@ Rcpp::NumericVector RcppDMI( size_t max_tau = static_cast(*std::max_element(tau_std.begin(), tau_std.end())); // ---- sort predict indices ---- - size_t max_lag = (tau == 0) - ? (max_E - 1) - : ((max_E - 1) * static_cast(std::abs(tau))); - pred_std.erase( std::remove_if(pred_std.begin(), pred_std.end(), [&](size_t idx){ return idx + 1 < max_tau; }), From 52399cfa37d5cf788faedffdf16ce292d42cfbfc Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 14/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index 151f74f..d723566 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -78,14 +78,9 @@ Rcpp::NumericVector RcppDMI( Rcpp::NumericVector result = Rcpp::wrap(res); Rcpp::CharacterVector resnames(result.size()); for (int i = 0; i < result.size(); ++i) { - resnames[i] = "tau:" + std::to_string(i + 1); + resnames[i] = "tau:" + std::to_string(tau_std[i]); } result.names() = resnames; - // Terminal-friendly hint (one-time, non-intrusive) - Rcpp::Rcout << "[fnn] Input tau E values exceeding max embeddable dimension were truncated, and values < 2 were clamped to 2.\n" - << "[fnn] Max embedding dimension E_max is auto-computed, with results returned for dimensions 1 through E_max.\n" - << "[fnn] Output 'tau:i' (where i = 1 to E_max-1) corresponds to the comparison between dimension i and i+1.\n"; - return result; } From 26c161e2abe70a61af95d3175dac23d330cc255e Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 15/21] correct code comments --- src/FNN.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FNN.cpp b/src/FNN.cpp index 13c2738..14a9e8d 100644 --- a/src/FNN.cpp +++ b/src/FNN.cpp @@ -199,7 +199,7 @@ Rcpp::NumericVector RcppFNN( // --- Check if full set is used --- bool use_subset = (selected_indices.size() < Mx.size()); - // --- Perform Pattern Causality Analysis --- + // --- Perform FNN Analysis --- std::vector res; if (!use_subset) @@ -244,7 +244,7 @@ Rcpp::NumericVector RcppFNN( pred_std[i] = index_map[pred_std[i]]; } - // --- Run patcaus on subset --- + // --- Run fnn on subset --- res = pc::fnn::fnn( Mx_sub, lib_std, pred_std, rt_std, eps_std, dist_metric, static_cast(std::abs(k)), From 528160bdbff2c280fe066d76a63d4fb70209b02e Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 16/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index d723566..2a39d6f 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "pc.h" // Wrapper function to perform delayed mutual information analysis @@ -44,7 +43,7 @@ Rcpp::NumericVector RcppDMI( // ---- sort predict indices ---- pred_std.erase( std::remove_if(pred_std.begin(), pred_std.end(), - [&](size_t idx){ return idx + 1 < max_tau; }), + [&](size_t idx){ return idx < max_tau; }), pred_std.end() ); From c3bb43394da3fe1e69c48e014e00b112d7dd3b19 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 17/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DMI.cpp b/src/DMI.cpp index 2a39d6f..c12829e 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -38,6 +38,9 @@ Rcpp::NumericVector RcppDMI( // Construct time delay step tau std::vector tau_std = Rcpp::as>(tau); + if (tau_std.empty()) { + Rcpp::stop("tau vector cannot be empty."); + } size_t max_tau = static_cast(*std::max_element(tau_std.begin(), tau_std.end())); // ---- sort predict indices ---- From e5cb8660aa2b94e27c26177a058884e8e5bcc445 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 18/21] draft rcpp wrapper for dmi --- src/DMI.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index c12829e..d7a15bb 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -57,16 +57,11 @@ Rcpp::NumericVector RcppDMI( ); // ---- filter pred (remove NaN in target/source) ---- - write = 0; - for (size_t i = 0; i < pred_std.size(); ++i) - { - size_t idx = pred_std[i]; - if (!std::isnan(tg[idx])) - { - pred_std[write++] = idx; - } - } - pred_std.resize(write); + pred_std.erase( + std::remove_if(pred_std.begin(), pred_std.end(), + [&](size_t idx){ return std::isnan(tg[idx]); }), + pred_std.end() + ); // --- Perform Delay Mutual Information Analysis --- std::vector res = pc::dmi::dmi( From fc7697c0c23665270b508d55dfcb87070b2396d3 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 19/21] unify code styles --- src/FNN.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/FNN.cpp b/src/FNN.cpp index 14a9e8d..6d71377 100644 --- a/src/FNN.cpp +++ b/src/FNN.cpp @@ -161,27 +161,17 @@ Rcpp::NumericVector RcppFNN( ); // ---- filter lib/pred (remove NaN in target/source) ---- - size_t write = 0; - for (size_t i = 0; i < lib_std.size(); ++i) - { - size_t idx = lib_std[i]; - if (!std::isnan(tg[idx])) - { - lib_std[write++] = idx; - } - } - lib_std.resize(write); + lib_std.erase( + std::remove_if(lib_std.begin(), lib_std.end(), + [&](size_t idx){ return std::isnan(tg[idx]); }), + lib_std.end() + ); - write = 0; - for (size_t i = 0; i < pred_std.size(); ++i) - { - size_t idx = pred_std[i]; - if (!std::isnan(tg[idx])) - { - pred_std[write++] = idx; - } - } - pred_std.resize(write); + pred_std.erase( + std::remove_if(pred_std.begin(), pred_std.end(), + [&](size_t idx){ return std::isnan(tg[idx]); }), + pred_std.end() + ); // --- Prepare for data slicing --- std::vector selected_indices; From f90fea1d78229149b4f253bbbd593a08459049c3 Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 20/21] unify code styles --- src/DMI.cpp | 2 +- src/FNN.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DMI.cpp b/src/DMI.cpp index d7a15bb..a7337c7 100644 --- a/src/DMI.cpp +++ b/src/DMI.cpp @@ -56,7 +56,7 @@ Rcpp::NumericVector RcppDMI( pred_std.end() ); - // ---- filter pred (remove NaN in target/source) ---- + // ---- filter pred (remove NaN in target) ---- pred_std.erase( std::remove_if(pred_std.begin(), pred_std.end(), [&](size_t idx){ return std::isnan(tg[idx]); }), diff --git a/src/FNN.cpp b/src/FNN.cpp index 6d71377..230ffc2 100644 --- a/src/FNN.cpp +++ b/src/FNN.cpp @@ -160,7 +160,7 @@ Rcpp::NumericVector RcppFNN( pred_std.end() ); - // ---- filter lib/pred (remove NaN in target/source) ---- + // ---- filter lib/pred (remove NaN in target) ---- lib_std.erase( std::remove_if(lib_std.begin(), lib_std.end(), [&](size_t idx){ return std::isnan(tg[idx]); }), From c79222d416c6219b04dfaf8a026b3e81f62c664e Mon Sep 17 00:00:00 2001 From: SpatLyu Date: Tue, 11 Aug 2026 00:00:01 +0800 Subject: [PATCH 21/21] export rcpp wrapper for dmi --- R/RcppExports.R | 4 ++++ src/RcppExports.cpp | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/R/RcppExports.R b/R/RcppExports.R index 7b3f4f2..7eab922 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,6 +1,10 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 +RcppDMI <- function(target, tau, pred, k = 3L, alg = 0L, base = 2.0, normalize = FALSE, threads = 1L) { + .Call(`_pc_RcppDMI`, target, tau, pred, k, alg, base, normalize, threads) +} + RcppFNN <- function(target, rt, eps, lib, pred, E, tau = 1L, style = 0L, dist_metric = "euclidean", k = 3L, threads = 1L, parallel_level = 0L, nb = NULL, nrows = NULL) { .Call(`_pc_RcppFNN`, target, rt, eps, lib, pred, E, tau, style, dist_metric, k, threads, parallel_level, nb, nrows) } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 902bf09..8fcfe42 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -12,6 +12,23 @@ Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif +// RcppDMI +Rcpp::NumericVector RcppDMI(const Rcpp::NumericVector& target, const Rcpp::NumericVector& tau, const Rcpp::IntegerVector& pred, int k, int alg, double base, bool normalize, int threads); +RcppExport SEXP _pc_RcppDMI(SEXP targetSEXP, SEXP tauSEXP, SEXP predSEXP, SEXP kSEXP, SEXP algSEXP, SEXP baseSEXP, SEXP normalizeSEXP, SEXP threadsSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::traits::input_parameter< const Rcpp::NumericVector& >::type target(targetSEXP); + Rcpp::traits::input_parameter< const Rcpp::NumericVector& >::type tau(tauSEXP); + Rcpp::traits::input_parameter< const Rcpp::IntegerVector& >::type pred(predSEXP); + Rcpp::traits::input_parameter< int >::type k(kSEXP); + Rcpp::traits::input_parameter< int >::type alg(algSEXP); + Rcpp::traits::input_parameter< double >::type base(baseSEXP); + Rcpp::traits::input_parameter< bool >::type normalize(normalizeSEXP); + Rcpp::traits::input_parameter< int >::type threads(threadsSEXP); + rcpp_result_gen = Rcpp::wrap(RcppDMI(target, tau, pred, k, alg, base, normalize, threads)); + return rcpp_result_gen; +END_RCPP +} // RcppFNN Rcpp::NumericVector RcppFNN(const Rcpp::NumericVector& target, const Rcpp::NumericVector& rt, const Rcpp::NumericVector& eps, const Rcpp::IntegerVector& lib, const Rcpp::IntegerVector& pred, const Rcpp::IntegerVector& E, int tau, int style, const std::string& dist_metric, int k, int threads, int parallel_level, Rcpp::Nullable nb, Rcpp::Nullable nrows); RcppExport SEXP _pc_RcppFNN(SEXP targetSEXP, SEXP rtSEXP, SEXP epsSEXP, SEXP libSEXP, SEXP predSEXP, SEXP ESEXP, SEXP tauSEXP, SEXP styleSEXP, SEXP dist_metricSEXP, SEXP kSEXP, SEXP threadsSEXP, SEXP parallel_levelSEXP, SEXP nbSEXP, SEXP nrowsSEXP) { @@ -120,6 +137,7 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { + {"_pc_RcppDMI", (DL_FUNC) &_pc_RcppDMI, 8}, {"_pc_RcppFNN", (DL_FUNC) &_pc_RcppFNN, 14}, {"_pc_RcppPC", (DL_FUNC) &_pc_RcppPC, 16}, {"_pc_RcppPCboot", (DL_FUNC) &_pc_RcppPCboot, 22},