diff --git a/R/set_smc_options.R b/R/set_smc_options.R index c2e0dcb..6d64c16 100644 --- a/R/set_smc_options.R +++ b/R/set_smc_options.R @@ -16,9 +16,6 @@ #' timestep. #' @param trace_latent Logical specifying whether to sample and save one #' complete set of latent rankings for each particle and each timepoint. -#' @param trace_directory Character specifying directory to create in which to -#' put parameter trace. Only used if `trace = TRUE`. If `trace_latent = TRUE` -#' also, then latent rankings are saved in the same directory. #' #' @return A list #' @export @@ -28,6 +25,6 @@ set_smc_options <- function( resampling_threshold = n_particles / 2, max_rejuvenation_steps = 20, metric = "footrule", resampler = "multinomial", latent_rank_proposal = "uniform", verbose = FALSE, - trace = FALSE, trace_latent = FALSE, trace_directory = "") { + trace = FALSE, trace_latent = FALSE) { as.list(environment()) } diff --git a/man/set_smc_options.Rd b/man/set_smc_options.Rd index 626f96d..a99625a 100644 --- a/man/set_smc_options.Rd +++ b/man/set_smc_options.Rd @@ -15,8 +15,7 @@ set_smc_options( latent_rank_proposal = "uniform", verbose = FALSE, trace = FALSE, - trace_latent = FALSE, - trace_directory = "" + trace_latent = FALSE ) } \arguments{ @@ -46,10 +45,6 @@ timestep.} \item{trace_latent}{Logical specifying whether to sample and save one complete set of latent rankings for each particle and each timepoint.} - -\item{trace_directory}{Character specifying directory to create in which to -put parameter trace. Only used if \code{trace = TRUE}. If \code{trace_latent = TRUE} -also, then latent rankings are saved in the same directory.} } \value{ A list diff --git a/src/options.cpp b/src/options.cpp index d9b6381..fa08a7a 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -11,5 +11,4 @@ Options::Options(const Rcpp::List& input_options) : max_rejuvenation_steps{input_options["max_rejuvenation_steps"]}, verbose{input_options["verbose"]}, trace{input_options["trace"]}, - trace_latent{input_options["trace_latent"]}, - trace_directory(input_options["trace_directory"]){} + trace_latent{input_options["trace_latent"]}{} diff --git a/src/options.h b/src/options.h index 7a2f7a7..f345677 100644 --- a/src/options.h +++ b/src/options.h @@ -17,5 +17,4 @@ struct Options{ const bool verbose; const bool trace; const bool trace_latent; - const std::string trace_directory; }; diff --git a/src/parameter_tracer.cpp b/src/parameter_tracer.cpp index ad23a14..571a095 100644 --- a/src/parameter_tracer.cpp +++ b/src/parameter_tracer.cpp @@ -5,21 +5,8 @@ #include "parameter_tracer.h" using namespace arma; -ParameterTracer::ParameterTracer(bool trace, bool trace_latent, const std::string& trace_directory) - : trace { trace }, trace_latent { trace_latent }, trace_directory { trace_directory } { - if(trace) { -#ifdef _WIN32 - // On Windows, mkdir takes only one argument - int status = mkdir(trace_directory.c_str()); -#else - // On POSIX systems, mkdir takes two arguments - int status = mkdir(trace_directory.c_str(), 0777); -#endif - if (status != 0) { - Rcpp::stop("Error creating trace directory."); - } - } -} +ParameterTracer::ParameterTracer(bool trace, bool trace_latent) + : trace { trace }, trace_latent { trace_latent } {} void ParameterTracer::update_trace(const std::vector& pvec, int t) { if(trace) { @@ -27,69 +14,33 @@ void ParameterTracer::update_trace(const std::vector& pvec, int t) { for(size_t i{}; i < pvec.size(); i++) { alpha.col(i) = pvec[i].parameters.alpha; } - - std::ostringstream filename_stream; - filename_stream << trace_directory << "/alpha_" << t << ".txt"; - std::string filename = filename_stream.str(); - - alpha.save(filename, arma_ascii); + alpha_traces.push_back(alpha); ucube rho(pvec[0].parameters.rho.n_rows, pvec[0].parameters.rho.n_cols, - pvec.size()); + pvec.size()); for(size_t i{}; i < pvec.size(); i++) { rho.slice(i) = pvec[i].parameters.rho; } - - std::ostringstream filename_stream_rho; - filename_stream_rho << trace_directory << "/rho_" << t << ".txt"; - std::string filename_rho = filename_stream_rho.str(); - - rho.save(filename_rho, arma_ascii); + rho_traces.push_back(rho); mat tau(pvec[0].parameters.tau.n_rows, pvec.size()); for(size_t i{}; i < pvec.size(); i++) { tau.col(i) = pvec[i].parameters.tau; } - - std::ostringstream filename_stream_tau; - filename_stream_tau << trace_directory << "/tau_" << t << ".txt"; - std::string filename_tau = filename_stream_tau.str(); - - tau.save(filename_tau, arma_ascii); + tau_traces.push_back(tau); vec log_importance_weights(pvec.size()); for(size_t i{}; i < pvec.size(); i++) { log_importance_weights(i) = pvec[i].log_importance_weight; } - - std::ostringstream filename_stream_log_weights; - filename_stream_log_weights << trace_directory << "/log_weights_" << t << ".txt"; - std::string filename_log_weights = filename_stream_log_weights.str(); - - log_importance_weights.save(filename_log_weights, arma_ascii); + log_importance_weights_traces.push_back(log_importance_weights); } if(trace_latent) { + std::vector current_latent_rankings; for(size_t i{}; i < pvec.size(); i++) { - std::ostringstream filename_stream_latent_rankings; - filename_stream_latent_rankings << trace_directory << "/latent_rankings" << t << "_" << i << ".bin"; - std::string filename_latent_rankings = filename_stream_latent_rankings.str(); - pvec[i].particle_filters[pvec[i].conditioned_particle_filter].latent_rankings.save(filename_latent_rankings); - } - // Create the zip file - std::ostringstream zip_command; - zip_command << "zip -jq " << trace_directory << "/latent_rankings" << t << ".zip " << trace_directory << "/latent_rankings" << t << "_*.bin"; - int zip_status = system(zip_command.str().c_str()); - if (zip_status != 0) { - Rcpp::stop("Error creating zip file."); - } - - // Delete the .bin files - std::ostringstream rm_command; - rm_command << "rm " << trace_directory << "/latent_rankings" << t << "_*.bin"; - int rm_status = system(rm_command.str().c_str()); - if (rm_status != 0) { - Rcpp::stop("Error deleting .bin files."); + current_latent_rankings.push_back(pvec[i].particle_filters[pvec[i].conditioned_particle_filter].latent_rankings); } + latent_rankings_traces.push_back(current_latent_rankings); } } diff --git a/src/parameter_tracer.h b/src/parameter_tracer.h index e6eaf73..33d34a9 100644 --- a/src/parameter_tracer.h +++ b/src/parameter_tracer.h @@ -3,10 +3,14 @@ #pragma once struct ParameterTracer{ - ParameterTracer(bool trace, bool trace_latent, const std::string& trace_directory); + ParameterTracer(bool trace, bool trace_latent); ~ParameterTracer() = default; bool trace; bool trace_latent; - std::string trace_directory; + std::vector alpha_traces{}; + std::vector rho_traces{}; + std::vector tau_traces{}; + std::vector log_importance_weights_traces{}; + std::vector> latent_rankings_traces{}; void update_trace(const std::vector& pvec, int t); }; diff --git a/src/run_smc.cpp b/src/run_smc.cpp index ea53b5d..15a455f 100644 --- a/src/run_smc.cpp +++ b/src/run_smc.cpp @@ -34,8 +34,7 @@ Rcpp::List run_smc( auto distfun = choose_distance_function(options.metric); auto resampler = choose_resampler(options.resampler); auto reporter = ProgressReporter(options.verbose); - auto tracer = ParameterTracer(options.trace, options.trace_latent, - options.trace_directory); + auto tracer = ParameterTracer(options.trace, options.trace_latent); Rcpp::IntegerVector n_particle_filters(data->n_timepoints()); double log_marginal_likelihood{}; @@ -140,6 +139,11 @@ Rcpp::List run_smc( Rcpp::Named("resampling") = resampling, Rcpp::Named("n_particle_filters") = n_particle_filters, Rcpp::Named("importance_weights") = exp(normalize_log_importance_weights(particle_vector)), - Rcpp::Named("log_marginal_likelihood") = log_marginal_likelihood + Rcpp::Named("log_marginal_likelihood") = log_marginal_likelihood, + Rcpp::Named("alpha_traces") = tracer.alpha_traces, + Rcpp::Named("rho_traces") = tracer.rho_traces, + Rcpp::Named("tau_traces") = tracer.tau_traces, + Rcpp::Named("log_importance_weights_traces") = tracer.log_importance_weights_traces, + Rcpp::Named("latent_rankings_traces") = tracer.latent_rankings_traces ); } diff --git a/tests/testthat/test-compute_sequentially_preferences.R b/tests/testthat/test-compute_sequentially_preferences.R index 4b87d17..54fbe8e 100644 --- a/tests/testthat/test-compute_sequentially_preferences.R +++ b/tests/testthat/test-compute_sequentially_preferences.R @@ -26,3 +26,59 @@ test_that("compute_sequentially works with preference data", { expect_gt(mean(mod$alpha), 1.03) expect_lt(mean(mod$alpha), 1.06) }) + +test_that("compute_sequentially works with preference data and tracing", { + dat <- subset(pairwise_preferences, user <= 3) + topological_sorts <- split(dat, f =~ timepoint) |> + lapply(split, f =~ user) |> + lapply(function(x) { + lapply(x, function(y) { + precompute_topological_sorts( + prefs = as.matrix(y[, c("top_item", "bottom_item"), drop = FALSE]), + n_items = 5, + save_frac = 1 + ) + }) + }) + + set.seed(2) + mod <- compute_sequentially( + data = dat, + hyperparameters = set_hyperparameters(n_items = 5), + smc_options = set_smc_options( + n_particles = 100, + max_rejuvenation_steps = 5, + trace = TRUE, trace_latent = FALSE + ), + topological_sorts = topological_sorts + ) + + expect_equal(length(mod$alpha_traces), 3) + expect_equal(length(mod$alpha_traces[[2]]), 100) + expect_gt(mod$alpha_traces[[2]][[3]], .7) + expect_lt(mod$alpha_traces[[2]][[3]], .8) + + set.seed(3) + mod <- compute_sequentially( + data = dat, + hyperparameters = set_hyperparameters(n_items = 5), + smc_options = set_smc_options( + n_particles = 100, + max_rejuvenation_steps = 5, + trace = TRUE, trace_latent = TRUE + ), + topological_sorts = topological_sorts + ) + + expect_equal(length(mod$alpha_traces), 3) + expect_equal(length(mod$alpha_traces[[2]]), 100) + expect_gt(mod$alpha_traces[[2]][[3]], .7) + expect_lt(mod$alpha_traces[[2]][[3]], .8) + + expect_equal(length(mod$latent_rankings_traces), 3) + expect_equal(length(mod$latent_rankings_traces[[2]]), 100) + expect_equal( + mod$latent_rankings_traces[[2]][[3]], + c(1, 2, 5, 3, 4, 2, 1, 4, 5, 3) + ) +})