diff --git a/NEWS.md b/NEWS.md index 1069428..a353bb2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,11 @@ ## Vietoris-Rips PH +## censored death values + +This version addresses #39 by encoding deaths that exceed the threshold as undefined (`NaN`) rather than infinite (`Inf`) then converting these values to missing (`NA_REAL`) while populating the `Rcpp::NumericMatrix` returned to R. +A single infinite degree-0 feature for the connected component is retained. + ### sliding window embeddings of multivariable time series (breaking change) Previously only univariable time series could be passed to `vietoris_rips()` via the sliding window embedding (used for quasi-attractor detection). diff --git a/R/data.r b/R/data.r index 90837f3..2c96d30 100644 --- a/R/data.r +++ b/R/data.r @@ -27,7 +27,7 @@ #' acre_coord <- aegypti[aegypti$state_code == "AC", c("x", "y"), drop = FALSE] #' acre_rips <- vietoris_rips(acre_coord) #' plot.new() -#' xymax <- max(setdiff(acre_rips$death, Inf)) +#' xymax <- max(setdiff(acre_rips$death, Inf), na.rm = TRUE) #' plot.window( #' xlim = c(0, xymax), #' ylim = c(0, xymax), diff --git a/man/aegypti.Rd b/man/aegypti.Rd index 1a512c1..2d0f827 100644 --- a/man/aegypti.Rd +++ b/man/aegypti.Rd @@ -36,7 +36,7 @@ and reverse-geocoded to states. acre_coord <- aegypti[aegypti$state_code == "AC", c("x", "y"), drop = FALSE] acre_rips <- vietoris_rips(acre_coord) plot.new() -xymax <- max(setdiff(acre_rips$death, Inf)) +xymax <- max(setdiff(acre_rips$death, Inf), na.rm = TRUE) plot.window( xlim = c(0, xymax), ylim = c(0, xymax), diff --git a/src/ripser.cpp b/src/ripser.cpp index 0868dfa..fd4c665 100644 --- a/src/ripser.cpp +++ b/src/ripser.cpp @@ -671,8 +671,10 @@ template class ripser { #endif // ripserq: Accumulate pairs in an object to be returned to the user. #ifdef COLLECT_PERSISTENCE_PAIRS - for (index_t i = 0; i < n; ++i) - if (dset.find(i) == i) persistence_pairs[0].emplace_back(0.0, std::numeric_limits::infinity()); + for (index_t i = 0; i < n - 1; ++i) + // ripserq: `quiet_NaN()` for deaths that subceed threshold. + if (dset.find(i) == i) persistence_pairs[0].emplace_back(0.0, std::numeric_limits::quiet_NaN()); + if (dset.find(n - 1) == n - 1) persistence_pairs[0].emplace_back(0.0, std::numeric_limits::infinity()); #endif } @@ -863,7 +865,8 @@ template class ripser { #endif // ripserq: Accumulate pairs in an object to be returned to the user. #ifdef COLLECT_PERSISTENCE_PAIRS - persistence_pairs[dim].emplace_back(diameter, std::numeric_limits::infinity()); + // ripserq: `quiet_NaN()` for deaths that subceed threshold. + persistence_pairs[dim].emplace_back(diameter, std::numeric_limits::quiet_NaN()); #endif break; } @@ -1404,7 +1407,10 @@ Rcpp::List ripser_cpp_dist(const Rcpp::NumericVector &dataset, int dim, double t Rcpp::NumericMatrix mat(pairs.size(), 2); for (size_t i = 0; i < pairs.size(); ++i) { mat(i, 0) = pairs[i].first; - mat(i, 1) = pairs[i].second; + if (std::isnan(pairs[i].second)) + mat(i, 1) = NA_REAL; + else + mat(i, 1) = pairs[i].second; } output[d] = mat; }