From 98b2add9588ce8243c55d155d51ef19190ede3a9 Mon Sep 17 00:00:00 2001
From: IsaccBarker <milobanks@rowlandhall.org>
Date: Tue, 14 Jan 2025 18:43:27 -0700
Subject: [PATCH] [core] update, fix #82

---
 .../epiworld/agent-meat-virus-sampling.hpp    |   6 +-
 include/epiworld/epiworld.hpp                 |   4 +-
 include/epiworld/math/lfmcmc/lfmcmc-bones.hpp | 177 ++++++-----
 .../math/lfmcmc/lfmcmc-meat-print.hpp         |  90 ++++--
 include/epiworld/math/lfmcmc/lfmcmc-meat.hpp  | 300 ++++++++++--------
 include/epiworld/misc.hpp                     |   2 +-
 include/epiworld/model-bones.hpp              |   6 +-
 include/epiworld/model-meat.hpp               |  38 +--
 include/epiworld/models/surveillance.hpp      |   2 +-
 include/epiworld/random_graph.hpp             |  13 +-
 10 files changed, 361 insertions(+), 277 deletions(-)

diff --git a/include/epiworld/agent-meat-virus-sampling.hpp b/include/epiworld/agent-meat-virus-sampling.hpp
index d728993..bfe668e 100644
--- a/include/epiworld/agent-meat-virus-sampling.hpp
+++ b/include/epiworld/agent-meat-virus-sampling.hpp
@@ -20,7 +20,7 @@ namespace sampler {
  * @return Virus<TSeq>* of the selected virus. If none selected (or none
  * available,) returns a nullptr;
  */
-template<typename TSeq>
+template<typename TSeq = EPI_DEFAULT_TSEQ>
 inline std::function<void(Agent<TSeq>*,Model<TSeq>*)> make_update_susceptible(
     std::vector< epiworld_fast_uint > exclude = {}
     )
@@ -179,7 +179,7 @@ inline std::function<void(Agent<TSeq>*,Model<TSeq>*)> make_update_susceptible(
  * @return Virus<TSeq>* of the selected virus. If none selected (or none
  * available,) returns a nullptr;
  */
-template<typename TSeq = int>
+template<typename TSeq = EPI_DEFAULT_TSEQ>
 inline std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> make_sample_virus_neighbors(
     std::vector< epiworld_fast_uint > exclude = {}
 )
@@ -347,7 +347,7 @@ inline std::function<Virus<TSeq>*(Agent<TSeq>*,Model<TSeq>*)> make_sample_virus_
  * @return Virus<TSeq>* of the selected virus. If none selected (or none
  * available,) returns a nullptr;
  */
-template<typename TSeq = int>
+template<typename TSeq = EPI_DEFAULT_TSEQ>
 inline Virus<TSeq> * sample_virus_single(Agent<TSeq> * p, Model<TSeq> * m)
 {
 
diff --git a/include/epiworld/epiworld.hpp b/include/epiworld/epiworld.hpp
index cfdee7a..6483465 100644
--- a/include/epiworld/epiworld.hpp
+++ b/include/epiworld/epiworld.hpp
@@ -18,7 +18,7 @@
 
 /* Versioning */
 #define EPIWORLD_VERSION_MAJOR 0
-#define EPIWORLD_VERSION_MINOR 4
+#define EPIWORLD_VERSION_MINOR 6
 #define EPIWORLD_VERSION_PATCH 0
 
 static const int epiworld_version_major = EPIWORLD_VERSION_MAJOR;
@@ -88,4 +88,4 @@ namespace epiworld {
 
 }
 
-#endif 
\ No newline at end of file
+#endif 
diff --git a/include/epiworld/math/lfmcmc/lfmcmc-bones.hpp b/include/epiworld/math/lfmcmc/lfmcmc-bones.hpp
index 6c494b9..46146a9 100755
--- a/include/epiworld/math/lfmcmc/lfmcmc-bones.hpp
+++ b/include/epiworld/math/lfmcmc/lfmcmc-bones.hpp
@@ -23,15 +23,15 @@ using LFMCMCKernelFun = std::function<epiworld_double(const std::vector< epiworl
 
 /**
  * @brief Proposal function
- * @param params_now Vector where to save the new parameters.
- * @param params_prev Vector of reference parameters.
+ * @param new_params Vector where to save the new parameters.
+ * @param old_params Vector of reference parameters.
  * @param m LFMCMC model.
  * @tparam TData 
  */
 template<typename TData>
 inline void proposal_fun_normal(
-    std::vector< epiworld_double >& params_now,
-    const std::vector< epiworld_double >& params_prev,
+    std::vector< epiworld_double >& new_params,
+    const std::vector< epiworld_double >& old_params,
     LFMCMC<TData>* m
 );
 
@@ -60,32 +60,32 @@ inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
  * Proposals are made within a radious 1 of the current
  * state of the parameters.
  * 
- * @param params_now Where to write the new parameters
- * @param params_prev Reference parameters
+ * @param new_params Where to write the new parameters
+ * @param old_params Reference parameters
  * @tparam TData 
  * @param m LFMCMC model.
  */
 template<typename TData>
 inline void proposal_fun_unif(
-    std::vector< epiworld_double >& params_now,
-    const std::vector< epiworld_double >& params_prev,
+    std::vector< epiworld_double >& new_params,
+    const std::vector< epiworld_double >& old_params,
     LFMCMC<TData>* m
 );
 
 /**
  * @brief Uses the uniform kernel with euclidean distance
  * 
- * @param stats_now Vector of current statistics based on 
- * simulated data.
- * @param stats_obs Vector of observed statistics
+ * @param simulated_stats Vector of statistics based on 
+ * simulated data
+ * @param observed_stats Vector of observed statistics
  * @param epsilon Epsilon parameter
- * @param m LFMCMC model.
+ * @param m LFMCMC model
  * @return epiworld_double 
  */
 template<typename TData>
 inline epiworld_double kernel_fun_uniform(
-    const std::vector< epiworld_double >& stats_now,
-    const std::vector< epiworld_double >& stats_obs,
+    const std::vector< epiworld_double >& simulated_stats,
+    const std::vector< epiworld_double >& observed_stats,
     epiworld_double epsilon,
     LFMCMC<TData>* m
 );
@@ -94,14 +94,17 @@ inline epiworld_double kernel_fun_uniform(
  * @brief Gaussian kernel
  * 
  * @tparam TData 
- * @param epsilon 
- * @param m 
+ * @param simulated_stats Vector of statistics based on 
+ * simulated data
+ * @param observed_stats Vector of observed statistics
+ * @param epsilon Epsilon parameter
+ * @param m LFMCMC model
  * @return epiworld_double 
  */
 template<typename TData>
 inline epiworld_double kernel_fun_gaussian(
-    const std::vector< epiworld_double >& stats_now,
-    const std::vector< epiworld_double >& stats_obs,
+    const std::vector< epiworld_double >& simulated_stats,
+    const std::vector< epiworld_double >& observed_stats,
     epiworld_double epsilon,
     LFMCMC<TData>* m
 );
@@ -116,7 +119,7 @@ class LFMCMC {
 private:
 
     // Random number sampling
-    std::mt19937 * engine = nullptr;
+    std::shared_ptr< std::mt19937 > m_engine = nullptr;
     
     std::shared_ptr< std::uniform_real_distribution<> > runifd =
         std::make_shared< std::uniform_real_distribution<> >(0.0, 1.0);
@@ -128,77 +131,89 @@ class LFMCMC {
         std::make_shared< std::gamma_distribution<> >();
 
     // Process data
-    TData * observed_data;
-    
-    // Information about the size of the problem
-    size_t n_samples;
-    size_t n_statistics;
-    size_t n_parameters;
+    TData m_observed_data;
+    std::vector< TData > * m_simulated_data = nullptr;
 
-    epiworld_double epsilon;
+    // Information about the size of the process
+    size_t m_n_samples;
+    size_t m_n_stats;
+    size_t m_n_params;
 
-    std::vector< epiworld_double > params_now;
-    std::vector< epiworld_double > params_prev;
-    std::vector< epiworld_double > params_init;
+    epiworld_double m_epsilon;
 
-    std::vector< epiworld_double > observed_stats; ///< Observed statistics
+    std::vector< epiworld_double > m_initial_params;             ///< Initial parameters
+    std::vector< epiworld_double > m_current_proposed_params;    ///< Proposed parameters for the next sample
+    std::vector< epiworld_double > m_current_accepted_params;    ///< Most recently accepted parameters (current state of MCMC)
+    std::vector< epiworld_double > m_current_proposed_stats;     ///< Statistics from simulation run with proposed parameters
+    std::vector< epiworld_double > m_current_accepted_stats;     ///< Statistics from simulation run with most recently accepted params
 
-    std::vector< epiworld_double > sampled_params;     ///< Sampled Parameters
-    std::vector< epiworld_double > sampled_stats;      ///< Sampled statistics
-    std::vector< epiworld_double > sampled_stats_prob; ///< Sampled statistics
-    std::vector< bool >            sampled_accepted;   ///< Indicator of accepted statistics
+    std::vector< epiworld_double > m_observed_stats;             ///< Observed statistics
 
-    std::vector< epiworld_double > accepted_params;      ///< Posterior distribution (accepted samples)
-    std::vector< epiworld_double > accepted_stats;       ///< Posterior distribution (accepted samples)
-    std::vector< epiworld_double > accepted_params_prob; ///< Posterior probability
+    std::vector< epiworld_double > m_all_sample_params;          ///< Parameter samples
+    std::vector< epiworld_double > m_all_sample_stats;           ///< Statistic samples
+    std::vector< bool >            m_all_sample_acceptance;      ///< Indicator if sample was accepted
+    std::vector< epiworld_double > m_all_sample_drawn_prob;      ///< Drawn probabilities (runif()) for each sample
+    std::vector< epiworld_double > m_all_sample_kernel_scores;   ///< Kernel scores for each sample
 
-    std::vector< epiworld_double > drawn_prob;     ///< Drawn probabilities (runif())
-    std::vector< TData > * sampled_data = nullptr;
+    std::vector< epiworld_double > m_all_accepted_params;        ///< Posterior distribution of parameters from accepted samples
+    std::vector< epiworld_double > m_all_accepted_stats;         ///< Posterior distribution of statistics from accepted samples
+    std::vector< epiworld_double > m_all_accepted_kernel_scores; ///< Kernel scores for each accepted sample
 
     // Functions
-    LFMCMCSimFun<TData> simulation_fun;
-    LFMCMCSummaryFun<TData> summary_fun;
-    LFMCMCProposalFun<TData> proposal_fun = proposal_fun_normal<TData>;
-    LFMCMCKernelFun<TData> kernel_fun     = kernel_fun_uniform<TData>;
+    LFMCMCSimFun<TData> m_simulation_fun;
+    LFMCMCSummaryFun<TData> m_summary_fun;
+    LFMCMCProposalFun<TData> m_proposal_fun = proposal_fun_normal<TData>;
+    LFMCMCKernelFun<TData> m_kernel_fun     = kernel_fun_uniform<TData>;
 
     // Misc
-    std::vector< std::string > names_parameters;
-    std::vector< std::string > names_statistics;
+    std::vector< std::string > m_param_names;
+    std::vector< std::string > m_stat_names;
 
-    std::chrono::time_point<std::chrono::steady_clock> time_start;
-    std::chrono::time_point<std::chrono::steady_clock> time_end;
+    std::chrono::time_point<std::chrono::steady_clock> m_start_time;
+    std::chrono::time_point<std::chrono::steady_clock> m_end_time;
 
+    // Timing
     // std::chrono::milliseconds
-    std::chrono::duration<epiworld_double,std::micro> time_elapsed = 
+    std::chrono::duration<epiworld_double,std::micro> m_elapsed_time = 
         std::chrono::duration<epiworld_double,std::micro>::zero();
 
-    inline void get_elapsed(
+    inline void get_elapsed_time(
         std::string unit,
         epiworld_double * last_elapsed,
         std::string * unit_abbr,
         bool print
-    );
+    ) const;
 
     void chrono_start();
     void chrono_end();
+
+    // Progress
+    bool verbose = true;
+    Progress progress_bar;
     
 public:
 
     void run(
-        std::vector< epiworld_double > param_init,
+        std::vector< epiworld_double > params_init_,
         size_t n_samples_,
-        epiworld_double epsilon_
+        epiworld_double epsilon_,
+        int seed = -1
         );
 
     LFMCMC() {};
-    LFMCMC(TData & observed_data_) : observed_data(&observed_data_) {};
+    LFMCMC(const TData & observed_data_) : m_observed_data(observed_data_) {};
     ~LFMCMC() {};
 
-    void set_observed_data(TData & observed_data_) {observed_data = &observed_data_;};
+    // Setting LFMCMC variables
+    void set_observed_data(const TData & observed_data_) {m_observed_data = observed_data_;};
+    
     void set_proposal_fun(LFMCMCProposalFun<TData> fun);
     void set_simulation_fun(LFMCMCSimFun<TData> fun);
     void set_summary_fun(LFMCMCSummaryFun<TData> fun);
     void set_kernel_fun(LFMCMCKernelFun<TData> fun);
+
+    void set_params_names(std::vector< std::string > names);
+    void set_stats_names(std::vector< std::string > names);
     
     /**
      * @name Random number generation
@@ -206,8 +221,8 @@ class LFMCMC {
      * @param eng 
      */
     ///@{
-    void set_rand_engine(std::mt19937 & eng);
-    std::mt19937 & get_rand_endgine();
+    void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
+    std::shared_ptr< std::mt19937 > & get_rand_endgine();
     void seed(epiworld_fast_uint s);
     void set_rand_gamma(epiworld_double alpha, epiworld_double beta);
     epiworld_double runif();
@@ -219,28 +234,38 @@ class LFMCMC {
     ///@}
 
     // Accessing parameters of the function
-    size_t get_n_samples() const {return n_samples;};
-    size_t get_n_statistics() const {return n_statistics;};
-    size_t get_n_parameters() const {return n_parameters;};
-    epiworld_double get_epsilon() const {return epsilon;};
-
-    const std::vector< epiworld_double > & get_params_now() {return params_now;};
-    const std::vector< epiworld_double > & get_params_prev() {return params_prev;};
-    const std::vector< epiworld_double > & get_params_init() {return params_init;};
-    const std::vector< epiworld_double > & get_statistics_obs() {return observed_stats;};
-    const std::vector< epiworld_double > & get_statistics_hist() {return sampled_stats;};
-    const std::vector< bool >            & get_statistics_accepted() {return sampled_accepted;};
-    const std::vector< epiworld_double > & get_posterior_lf_prob() {return accepted_params_prob;};
-    const std::vector< epiworld_double > & get_drawn_prob() {return drawn_prob;};
-    std::vector< TData > * get_sampled_data() {return sampled_data;};
-
-    void set_par_names(std::vector< std::string > names);
-    void set_stats_names(std::vector< std::string > names);
+    size_t get_n_samples() const {return m_n_samples;};
+    size_t get_n_stats() const {return m_n_stats;};
+    size_t get_n_params() const {return m_n_params;};
+    epiworld_double get_epsilon() const {return m_epsilon;};
+
+    const std::vector< epiworld_double > & get_initial_params() const {return m_initial_params;};
+    const std::vector< epiworld_double > & get_current_proposed_params() const {return m_current_proposed_params;};
+    const std::vector< epiworld_double > & get_current_accepted_params() const {return m_current_accepted_params;};
+    const std::vector< epiworld_double > & get_current_proposed_stats() const {return m_current_proposed_stats;};
+    const std::vector< epiworld_double > & get_current_accepted_stats() const {return m_current_accepted_stats;};
+
+    const std::vector< epiworld_double > & get_observed_stats() const {return m_observed_stats;};
+
+    const std::vector< epiworld_double > & get_all_sample_params() const {return m_all_sample_params;};
+    const std::vector< epiworld_double > & get_all_sample_stats() const {return m_all_sample_stats;};
+    const std::vector< bool >            & get_all_sample_acceptance() const {return m_all_sample_acceptance;};
+    const std::vector< epiworld_double > & get_all_sample_drawn_prob() const {return m_all_sample_drawn_prob;};
+    const std::vector< epiworld_double > & get_all_sample_kernel_scores() const {return m_all_sample_kernel_scores;};
+
+    const std::vector< epiworld_double > & get_all_accepted_params() const {return m_all_accepted_params;};
+    const std::vector< epiworld_double > & get_all_accepted_stats() const {return m_all_accepted_stats;};
+    const std::vector< epiworld_double > & get_all_accepted_kernel_scores() const {return m_all_accepted_kernel_scores;};
+    
+    std::vector< TData > * get_simulated_data() const {return m_simulated_data;};
 
-    std::vector< epiworld_double > get_params_mean();
-    std::vector< epiworld_double > get_stats_mean();
+    std::vector< epiworld_double > get_mean_params();
+    std::vector< epiworld_double > get_mean_stats();
 
-    void print() ;
+    // Printing
+    LFMCMC<TData> & verbose_off();
+    LFMCMC<TData> & verbose_on();
+    void print(size_t burnin = 0u) const;
 
 };
 
diff --git a/include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp b/include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp
index 38cbf56..6a658ab 100755
--- a/include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp
+++ b/include/epiworld/math/lfmcmc/lfmcmc-meat-print.hpp
@@ -2,61 +2,83 @@
 #define LFMCMC_MEAT_PRINT_HPP
 
 template<typename TData>
-inline void LFMCMC<TData>::print()
+inline void LFMCMC<TData>::print(size_t burnin) const
 {
-    std::vector< epiworld_double > summ_params(n_parameters * 3, 0.0);
-    std::vector< epiworld_double > summ_stats(n_statistics * 3, 0.0);
 
-    for (size_t k = 0u; k < n_parameters; ++k)
+    // For each statistic or parameter in the model, we print three values: 
+    // - mean, the 2.5% quantile, and the 97.5% quantile
+    std::vector< epiworld_double > summ_params(m_n_params * 3, 0.0);
+    std::vector< epiworld_double > summ_stats(m_n_stats * 3, 0.0);
+
+    // Compute the number of samples to use based on burnin rate
+    size_t n_samples_print = m_n_samples;
+    if (burnin > 0)
+    {
+        if (burnin >= m_n_samples)
+            throw std::length_error(
+                "The burnin is greater than or equal to the number of samples."
+                );
+
+        n_samples_print = m_n_samples - burnin;
+
+    }
+
+    epiworld_double n_samples_dbl = static_cast< epiworld_double >(
+        n_samples_print
+        );
+
+    // Compute parameter summary values
+    for (size_t k = 0u; k < m_n_params; ++k)
     {
 
         // Retrieving the relevant parameter
-        std::vector< epiworld_double > par_i(n_samples);
-        for (size_t i = 0u; i < n_samples; ++i)
+        std::vector< epiworld_double > par_i(n_samples_print);
+        for (size_t i = burnin; i < m_n_samples; ++i)
         {
-            par_i[i] = accepted_params[i * n_parameters + k];
-            summ_params[k * 3] += par_i[i]/n_samples;
+            par_i[i-burnin] = m_all_accepted_params[i * m_n_params + k];
+            summ_params[k * 3] += par_i[i-burnin]/n_samples_dbl;
         }
 
         // Computing the 95% Credible interval
         std::sort(par_i.begin(), par_i.end());
 
         summ_params[k * 3 + 1u] = 
-            par_i[std::floor(.025 * static_cast<epiworld_double>(n_samples))];
+            par_i[std::floor(.025 * n_samples_dbl)];
         summ_params[k * 3 + 2u] = 
-            par_i[std::floor(.975 * static_cast<epiworld_double>(n_samples))];
+            par_i[std::floor(.975 * n_samples_dbl)];
 
     }
 
-    for (size_t k = 0u; k < n_statistics; ++k)
+    // Compute statistics summary values
+    for (size_t k = 0u; k < m_n_stats; ++k)
     {
 
         // Retrieving the relevant parameter
-        std::vector< epiworld_double > stat_k(n_samples);
-        for (size_t i = 0u; i < n_samples; ++i)
+        std::vector< epiworld_double > stat_k(n_samples_print);
+        for (size_t i = burnin; i < m_n_samples; ++i)
         {
-            stat_k[i] = accepted_stats[i * n_statistics + k];
-            summ_stats[k * 3] += stat_k[i]/n_samples;
+            stat_k[i-burnin] = m_all_accepted_stats[i * m_n_stats + k];
+            summ_stats[k * 3] += stat_k[i-burnin]/n_samples_dbl;
         }
 
         // Computing the 95% Credible interval
         std::sort(stat_k.begin(), stat_k.end());
-
         summ_stats[k * 3 + 1u] = 
-            stat_k[std::floor(.025 * static_cast<epiworld_double>(n_samples))];
+            stat_k[std::floor(.025 * n_samples_dbl)];
         summ_stats[k * 3 + 2u] = 
-            stat_k[std::floor(.975 * static_cast<epiworld_double>(n_samples))];
+            stat_k[std::floor(.975 * n_samples_dbl)];
 
     }
 
     printf_epiworld("___________________________________________\n\n");
     printf_epiworld("LIKELIHOOD-FREE MARKOV CHAIN MONTE CARLO\n\n");
 
-    printf_epiworld("N Samples : %ld\n", n_samples);
+    printf_epiworld("N Samples (total) : %zu\n", m_n_samples);
+    printf_epiworld("N Samples (after burn-in period) : %zu\n", m_n_samples - burnin);
 
     std::string abbr;
     epiworld_double elapsed;
-    get_elapsed("auto", &elapsed, &abbr, false);
+    get_elapsed_time("auto", &elapsed, &abbr, false);
     printf_epiworld("Elapsed t : %.2f%s\n\n", elapsed, abbr.c_str());
     
     ////////////////////////////////////////////////////////////////////////////
@@ -78,10 +100,10 @@ inline void LFMCMC<TData>::print()
     nchar_par_num += 5; // 1 for neg padd, 2 for decimals, 1 the decimal point, and one b/c log(<10) < 1.
     std::string charlen = std::to_string(nchar_par_num);
 
-    if (names_parameters.size() != 0u)
+    if (m_param_names.size() != 0u)
     {
         int nchar_par = 0;
-        for (auto & n : names_parameters)
+        for (auto & n : m_param_names)
         {
             int tmp_nchar = n.length();
             if (nchar_par < tmp_nchar)
@@ -96,15 +118,15 @@ inline void LFMCMC<TData>::print()
             std::string(".2f] (initial : % ") +
             charlen + std::string(".2f)\n");
 
-        for (size_t k = 0u; k < n_parameters; ++k)
+        for (size_t k = 0u; k < m_n_params; ++k)
         {
             printf_epiworld(
                 fmt_params.c_str(),
-                names_parameters[k].c_str(),
+                m_param_names[k].c_str(),
                 summ_params[k * 3],
                 summ_params[k * 3 + 1u],
                 summ_params[k * 3 + 2u],
-                params_init[k]
+                m_initial_params[k]
                 );
         }
 
@@ -117,7 +139,7 @@ inline void LFMCMC<TData>::print()
             std::string(".2f] (initial : % ") + charlen +
             std::string(".2f)\n");
 
-        for (size_t k = 0u; k < n_parameters; ++k)
+        for (size_t k = 0u; k < m_n_params; ++k)
         {
             
             printf_epiworld(
@@ -126,7 +148,7 @@ inline void LFMCMC<TData>::print()
                 summ_params[k * 3],
                 summ_params[k * 3 + 1u],
                 summ_params[k * 3 + 2u],
-                params_init[k]
+                m_initial_params[k]
                 );
         }
 
@@ -150,10 +172,10 @@ inline void LFMCMC<TData>::print()
 
     // Figuring out format
     std::string fmt_stats;
-    if (names_statistics.size() != 0u)
+    if (m_stat_names.size() != 0u)
     {
         int nchar_stats = 0;
-        for (auto & n : names_statistics)
+        for (auto & n : m_stat_names)
         {
             int tmp_nchar = n.length();
             if (nchar_stats < tmp_nchar)
@@ -168,15 +190,15 @@ inline void LFMCMC<TData>::print()
             std::string(".2f] (Observed: % ") + nchar_char +
             std::string(".2f)\n");
 
-        for (size_t k = 0u; k < n_statistics; ++k)
+        for (size_t k = 0u; k < m_n_stats; ++k)
         {
             printf_epiworld(
                 fmt_stats.c_str(),
-                names_statistics[k].c_str(),
+                m_stat_names[k].c_str(),
                 summ_stats[k * 3],
                 summ_stats[k * 3 + 1u],
                 summ_stats[k * 3 + 2u],
-                observed_stats[k]
+                m_observed_stats[k]
                 );
         }
 
@@ -190,7 +212,7 @@ inline void LFMCMC<TData>::print()
             std::string(".2f] (Observed: % ") + nchar_char +
             std::string(".2f)\n");
 
-        for (size_t k = 0u; k < n_statistics; ++k)
+        for (size_t k = 0u; k < m_n_stats; ++k)
         {
             printf_epiworld(
                 fmt_stats.c_str(),
@@ -198,7 +220,7 @@ inline void LFMCMC<TData>::print()
                 summ_stats[k * 3],
                 summ_stats[k * 3 + 1u],
                 summ_stats[k * 3 + 2u],
-                observed_stats[k]
+                m_observed_stats[k]
                 );
         }
 
diff --git a/include/epiworld/math/lfmcmc/lfmcmc-meat.hpp b/include/epiworld/math/lfmcmc/lfmcmc-meat.hpp
index 688f4fd..239f5fa 100755
--- a/include/epiworld/math/lfmcmc/lfmcmc-meat.hpp
+++ b/include/epiworld/math/lfmcmc/lfmcmc-meat.hpp
@@ -5,20 +5,20 @@
 
 /**
  * @brief Proposal function
- * @param params_now Vector where to save the new parameters.
- * @param params_prev Vector of reference parameters.
+ * @param new_params Vector where to save the new parameters.
+ * @param old_params Vector of reference parameters.
  * @param m LFMCMC model.
  * @tparam TData 
  */
 template<typename TData>
 inline void proposal_fun_normal(
-    std::vector< epiworld_double >& params_now,
-    const std::vector< epiworld_double >& params_prev,
+    std::vector< epiworld_double >& new_params,
+    const std::vector< epiworld_double >& old_params,
     LFMCMC<TData>* m
 ) {
 
-    for (size_t p = 0u; p < m->get_n_parameters(); ++p)
-        params_now[p] = params_prev[p] + m->rnorm();
+    for (size_t p = 0u; p < m->get_n_params(); ++p)
+        new_params[p] = old_params[p] + m->rnorm();
 
     return;
 }
@@ -44,20 +44,20 @@ inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
 
     LFMCMCProposalFun<TData> fun =
         [scale,lb,ub](
-            std::vector< epiworld_double >& params_now,
-            const std::vector< epiworld_double >& params_prev,
+            std::vector< epiworld_double >& new_params,
+            const std::vector< epiworld_double >& old_params,
             LFMCMC<TData>* m
         ) {
 
         // Making the proposal
-        for (size_t p = 0u; p < m->get_n_parameters(); ++p)
-            params_now[p] = params_prev[p] + m->rnorm() * scale;
+        for (size_t p = 0u; p < m->get_n_params(); ++p)
+            new_params[p] = old_params[p] + m->rnorm() * scale;
 
         // Checking boundaries
         epiworld_double d = ub - lb;
         int odd;
         epiworld_double d_above, d_below;
-        for (auto & p : params_now)
+        for (auto & p : new_params)
         {
 
             // Correcting if parameter goes above the upper bound
@@ -84,7 +84,7 @@ inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
         }
 
         #ifdef EPI_DEBUG
-        for (auto & p : params_now)
+        for (auto & p : new_params)
             if (p < lb || p > ub)
                 throw std::range_error("The parameter is out of bounds.");
         #endif
@@ -103,20 +103,20 @@ inline LFMCMCProposalFun<TData> make_proposal_norm_reflective(
  * Proposals are made within a radious 1 of the current
  * state of the parameters.
  * 
- * @param params_now Where to write the new parameters
- * @param params_prev Reference parameters
+ * @param new_params Where to write the new parameters
+ * @param old_params Reference parameters
  * @tparam TData 
  * @param m LFMCMC model.
  */
 template<typename TData>
 inline void proposal_fun_unif(
-    std::vector< epiworld_double >& params_now,
-    const std::vector< epiworld_double >& params_prev,
+    std::vector< epiworld_double >& new_params,
+    const std::vector< epiworld_double >& old_params,
     LFMCMC<TData>* m
 ) {
 
-    for (size_t p = 0u; p < m->get_n_parameters(); ++p)
-        params_now[p] = (params_prev[p] + m->runif(-1.0, 1.0));
+    for (size_t p = 0u; p < m->get_n_params(); ++p)
+        new_params[p] = (old_params[p] + m->runif(-1.0, 1.0));
 
     return;
 }
@@ -124,24 +124,24 @@ inline void proposal_fun_unif(
 /**
  * @brief Uses the uniform kernel with euclidean distance
  * 
- * @param stats_now Vector of current statistics based on 
- * simulated data.
- * @param stats_obs Vector of observed statistics
+ * @param simulated_stats Vector of statistics based on 
+ * simulated data
+ * @param observed_stats Vector of observed statistics
  * @param epsilon Epsilon parameter
- * @param m LFMCMC model.
+ * @param m LFMCMC model
  * @return epiworld_double 
  */
 template<typename TData>
 inline epiworld_double kernel_fun_uniform(
-    const std::vector< epiworld_double >& stats_now,
-    const std::vector< epiworld_double >& stats_obs,
+    const std::vector< epiworld_double >& simulated_stats,
+    const std::vector< epiworld_double >& observed_stats,
     epiworld_double epsilon,
     LFMCMC<TData>* m
 ) {
 
     epiworld_double ans = 0.0;
-    for (size_t p = 0u; p < m->get_n_parameters(); ++p)
-        ans += std::pow(stats_obs[p] - stats_now[p], 2.0);
+    for (size_t p = 0u; p < m->get_n_params(); ++p)
+        ans += std::pow(observed_stats[p] - simulated_stats[p], 2.0);
 
     return std::sqrt(ans) < epsilon ? 1.0 : 0.0;
 
@@ -153,21 +153,24 @@ inline epiworld_double kernel_fun_uniform(
  * @brief Gaussian kernel
  * 
  * @tparam TData 
- * @param epsilon 
- * @param m 
+ * @param simulated_stats Vector of statistics based on 
+ * simulated data
+ * @param observed_stats Vector of observed statistics
+ * @param epsilon Epsilon parameter
+ * @param m LFMCMC model
  * @return epiworld_double 
  */
 template<typename TData>
 inline epiworld_double kernel_fun_gaussian(
-    const std::vector< epiworld_double >& stats_now,
-    const std::vector< epiworld_double >& stats_obs,
+    const std::vector< epiworld_double >& simulated_stats,
+    const std::vector< epiworld_double >& observed_stats,
     epiworld_double epsilon,
     LFMCMC<TData>* m
 ) {
 
     epiworld_double ans = 0.0;
-    for (size_t p = 0u; p < m->get_n_parameters(); ++p)
-        ans += std::pow(stats_obs[p] - stats_now[p], 2.0);
+    for (size_t p = 0u; p < m->get_n_params(); ++p)
+        ans += std::pow(observed_stats[p] - simulated_stats[p], 2.0);
 
     return std::exp(
         -.5 * (ans/std::pow(1 + std::pow(epsilon, 2.0)/3.0, 2.0))
@@ -179,25 +182,25 @@ inline epiworld_double kernel_fun_gaussian(
 template<typename TData>
 inline void LFMCMC<TData>::set_proposal_fun(LFMCMCProposalFun<TData> fun)
 {
-    proposal_fun = fun;
+    m_proposal_fun = fun;
 }
 
 template<typename TData>
 inline void LFMCMC<TData>::set_simulation_fun(LFMCMCSimFun<TData> fun)
 {
-    simulation_fun = fun;
+    m_simulation_fun = fun;
 }
 
 template<typename TData>
 inline void LFMCMC<TData>::set_summary_fun(LFMCMCSummaryFun<TData> fun)
 {
-    summary_fun = fun;
+    m_summary_fun = fun;
 }
 
 template<typename TData>
 inline void LFMCMC<TData>::set_kernel_fun(LFMCMCKernelFun<TData> fun)
 {
-    kernel_fun = fun;
+    m_kernel_fun = fun;
 }
 
 
@@ -205,7 +208,8 @@ template<typename TData>
 inline void LFMCMC<TData>::run(
     std::vector< epiworld_double > params_init_,
     size_t n_samples_,
-    epiworld_double epsilon_
+    epiworld_double epsilon_,
+    int seed
     )
 {
 
@@ -213,100 +217,128 @@ inline void LFMCMC<TData>::run(
     chrono_start();
 
     // Setting the baseline parameters of the model
-    n_samples    = n_samples_;
-    epsilon      = epsilon_;
-    params_init  = params_init_;
-    n_parameters = params_init_.size();
+    m_n_samples    = n_samples_;
+    m_epsilon      = epsilon_;
+    m_initial_params  = params_init_;
+    m_n_params = params_init_.size();
+
+    if (seed >= 0)
+        this->seed(seed);
 
-    params_now.resize(n_parameters);
-    params_prev.resize(n_parameters);
+    m_current_proposed_params.resize(m_n_params);
+    m_current_accepted_params.resize(m_n_params);
 
-    if (sampled_data != nullptr)
-        sampled_data->resize(n_samples);
+    if (m_simulated_data != nullptr)
+        m_simulated_data->resize(m_n_samples);
 
-    params_prev = params_init;
-    params_now  = params_init;
+    m_current_accepted_params = m_initial_params;
+    m_current_proposed_params  = m_initial_params;
 
     // Computing the baseline sufficient statistics
-    summary_fun(observed_stats, *observed_data, this);
-    n_statistics = observed_stats.size();
+    m_summary_fun(m_observed_stats, m_observed_data, this);
+    m_n_stats = m_observed_stats.size();
 
     // Reserving size
-    drawn_prob.resize(n_samples);
-    sampled_accepted.resize(n_samples, false);
-    sampled_stats.resize(n_samples * n_statistics);
-    sampled_stats_prob.resize(n_samples);
+    m_current_proposed_stats.resize(m_n_stats);
+    m_current_accepted_stats.resize(m_n_stats);
+    m_all_sample_drawn_prob.resize(m_n_samples);
+    m_all_sample_acceptance.resize(m_n_samples, false);
+    m_all_sample_params.resize(m_n_samples * m_n_params);
+    m_all_sample_stats.resize(m_n_samples * m_n_stats);
+    m_all_sample_kernel_scores.resize(m_n_samples);
 
-    accepted_params.resize(n_samples * n_parameters);
-    accepted_stats.resize(n_samples * n_statistics);
-    accepted_params_prob.resize(n_samples);
+    m_all_accepted_params.resize(m_n_samples * m_n_params);
+    m_all_accepted_stats.resize(m_n_samples * m_n_stats);
+    m_all_accepted_kernel_scores.resize(m_n_samples);
 
-    TData data_i = simulation_fun(params_init, this);
+    TData data_i = m_simulation_fun(m_initial_params, this);
 
-    std::vector< epiworld_double > proposed_stats_i;
-    summary_fun(proposed_stats_i, data_i, this);
-    accepted_params_prob[0u] = kernel_fun(proposed_stats_i, observed_stats, epsilon, this);
+    m_summary_fun(m_current_proposed_stats, data_i, this);
+    m_all_accepted_kernel_scores[0u] = m_kernel_fun(
+        m_current_proposed_stats, m_observed_stats, m_epsilon, this
+        );
 
     // Recording statistics
-    for (size_t i = 0u; i < n_statistics; ++i)
-        sampled_stats[i] = proposed_stats_i[i];
+    for (size_t i = 0u; i < m_n_stats; ++i)
+        m_all_sample_stats[i] = m_current_proposed_stats[i];
+    
+    m_current_accepted_stats = m_current_proposed_stats;
 
-    for (size_t k = 0u; k < n_statistics; ++k)
-        accepted_params[k] = proposed_stats_i[k];
+    for (size_t k = 0u; k < m_n_params; ++k)
+        m_all_accepted_params[k] = m_initial_params[k];
+    
+    for (size_t k = 0u; k < m_n_params; ++k)
+        m_all_sample_params[k] = m_initial_params[k];
    
-    for (size_t i = 1u; i < n_samples; ++i)
+    // Init progress bar
+    progress_bar = Progress(m_n_samples, 80);
+    if (verbose) { 
+        progress_bar.next(); 
+    }
+
+    // Run LFMCMC
+    for (size_t i = 1u; i < m_n_samples; ++i)
     {
-        // Step 1: Generate a proposal and store it in params_now
-        proposal_fun(params_now, params_prev, this);
+        // Step 1: Generate a proposal and store it in m_current_proposed_params
+        m_proposal_fun(m_current_proposed_params, m_current_accepted_params, this);
 
-        // Step 2: Using params_now, simulate data
-        TData data_i = simulation_fun(params_now, this);
+        // Step 2: Using m_current_proposed_params, simulate data
+        TData data_i = m_simulation_fun(m_current_proposed_params, this);
 
         // Are we storing the data?
-        if (sampled_data != nullptr)
-            sampled_data->operator[](i) = data_i;
+        if (m_simulated_data != nullptr)
+            m_simulated_data->operator[](i) = data_i;
 
         // Step 3: Generate the summary statistics of the data
-        summary_fun(proposed_stats_i, data_i, this);
+        m_summary_fun(m_current_proposed_stats, data_i, this);
 
         // Step 4: Compute the hastings ratio using the kernel function
-        epiworld_double hr = kernel_fun(proposed_stats_i, observed_stats, epsilon, this);
-        sampled_stats_prob[i] = hr;
+        epiworld_double hr = m_kernel_fun(
+            m_current_proposed_stats, m_observed_stats, m_epsilon, this
+            );
+
+        m_all_sample_kernel_scores[i] = hr;
 
         // Storing data
-        for (size_t k = 0u; k < n_statistics; ++k)
-            sampled_stats[i * n_statistics + k] = proposed_stats_i[k];
+        for (size_t k = 0u; k < m_n_params; ++k)
+            m_all_sample_params[i * m_n_params + k] = m_current_proposed_params[k];
+
+        for (size_t k = 0u; k < m_n_stats; ++k)
+            m_all_sample_stats[i * m_n_stats + k] = m_current_proposed_stats[k];
         
         // Running Hastings ratio
-        epiworld_double r      = runif();
-        drawn_prob[i] = r;
+        epiworld_double r = runif();
+        m_all_sample_drawn_prob[i] = r;
 
         // Step 5: Update if likely
-        if (r < std::min(static_cast<epiworld_double>(1.0), hr / accepted_params_prob[i - 1u]))
+        if (r < std::min(static_cast<epiworld_double>(1.0), hr / m_all_accepted_kernel_scores[i - 1u]))
         {
-            accepted_params_prob[i] = hr;
-            sampled_accepted[i]     = true;
+            m_all_accepted_kernel_scores[i] = hr;
+            m_all_sample_acceptance[i]     = true;
             
-            for (size_t k = 0u; k < n_statistics; ++k)
-                accepted_stats[i * n_statistics + k] =
-                    proposed_stats_i[k];
-
-            params_prev = params_now;
+            for (size_t k = 0u; k < m_n_stats; ++k)
+                m_all_accepted_stats[i * m_n_stats + k] =
+                    m_current_proposed_stats[k];
 
+            m_current_accepted_params = m_current_proposed_params;
+            m_current_accepted_stats = m_current_proposed_stats;
         } else
         {
 
-            for (size_t k = 0u; k < n_statistics; ++k)
-                accepted_stats[i * n_statistics + k] =
-                    accepted_stats[(i - 1) * n_statistics + k];
+            for (size_t k = 0u; k < m_n_stats; ++k)
+                m_all_accepted_stats[i * m_n_stats + k] =
+                    m_all_accepted_stats[(i - 1) * m_n_stats + k];
 
-            accepted_params_prob[i] = accepted_params_prob[i - 1u];
+            m_all_accepted_kernel_scores[i] = m_all_accepted_kernel_scores[i - 1u];
         }
             
 
-        for (size_t k = 0u; k < n_parameters; ++k)
-            accepted_params[i * n_parameters + k] = params_prev[k];
+        for (size_t k = 0u; k < m_n_params; ++k)
+            m_all_accepted_params[i * m_n_params + k] = m_current_accepted_params[k];
 
+        if (verbose) { 
+            progress_bar.next(); 
+        }
     }
 
     // End timing
@@ -318,7 +350,7 @@ inline void LFMCMC<TData>::run(
 template<typename TData>
 inline epiworld_double LFMCMC<TData>::runif()
 {
-    return runifd->operator()(*engine);
+    return runifd->operator()(*m_engine);
 }
 
 template<typename TData>
@@ -327,13 +359,13 @@ inline epiworld_double LFMCMC<TData>::runif(
     epiworld_double ub
 )
 {
-    return runifd->operator()(*engine) * (ub - lb) + lb;
+    return runifd->operator()(*m_engine) * (ub - lb) + lb;
 }
 
 template<typename TData>
 inline epiworld_double LFMCMC<TData>::rnorm()
 {
-    return rnormd->operator()(*engine);
+    return rnormd->operator()(*m_engine);
 }
 
 template<typename TData>
@@ -342,13 +374,13 @@ inline epiworld_double LFMCMC<TData>::rnorm(
     epiworld_double sd
     )
 {
-    return (rnormd->operator()(*engine)) * sd + mean;
+    return (rnormd->operator()(*m_engine)) * sd + mean;
 }
 
 template<typename TData>
 inline epiworld_double LFMCMC<TData>::rgamma()
 {
-    return rgammad->operator()(*engine);
+    return rgammad->operator()(*m_engine);
 }
 
 template<typename TData>
@@ -362,7 +394,7 @@ inline epiworld_double LFMCMC<TData>::rgamma(
 
     rgammad->param(std::gamma_distribution<>::param_type(alpha, beta));
 
-    epiworld_double ans = rgammad->operator()(*engine);
+    epiworld_double ans = rgammad->operator()(*m_engine);
 
     rgammad->param(old_param);
 
@@ -373,14 +405,14 @@ inline epiworld_double LFMCMC<TData>::rgamma(
 template<typename TData>
 inline void LFMCMC<TData>::seed(epiworld_fast_uint s) {
 
-    this->engine->seed(s);
+    this->m_engine->seed(s);
 
 }
 
 template<typename TData>
-inline void LFMCMC<TData>::set_rand_engine(std::mt19937 & eng)
+inline void LFMCMC<TData>::set_rand_engine(std::shared_ptr< std::mt19937 > & eng)
 {
-    engine = &eng;
+    m_engine = eng;
 }
 
 template<typename TData>
@@ -390,9 +422,9 @@ inline void LFMCMC<TData>::set_rand_gamma(epiworld_double alpha, epiworld_double
 }
 
 template<typename TData>
-inline std::mt19937 & LFMCMC<TData>::get_rand_endgine()
+inline std::shared_ptr< std::mt19937 > & LFMCMC<TData>::get_rand_endgine()
 {
-    return *engine;
+    return m_engine;
 }
 
 // Step 1: Simulate data
@@ -405,16 +437,16 @@ inline std::mt19937 & LFMCMC<TData>::get_rand_endgine()
 
 #define DURCAST(tunit,txtunit) {\
         elapsed       = std::chrono::duration_cast<std::chrono:: tunit>(\
-            time_end - time_start).count(); \
+            m_end_time - m_start_time).count(); \
         abbr_unit     = txtunit;}
 
 template<typename TData>
-inline void LFMCMC<TData>::get_elapsed(
+inline void LFMCMC<TData>::get_elapsed_time(
     std::string unit,
     epiworld_double * last_elapsed,
     std::string * unit_abbr,
     bool print
-) {
+) const {
 
     // Preparing the result
     epiworld_double elapsed;
@@ -425,7 +457,7 @@ inline void LFMCMC<TData>::get_elapsed(
     {
 
         size_t tlength = std::to_string(
-            static_cast<int>(floor(time_elapsed.count()))
+            static_cast<int>(floor(m_elapsed_time.count()))
             ).length();
         
         if (tlength <= 1)
@@ -470,46 +502,46 @@ inline void LFMCMC<TData>::get_elapsed(
 
 template<typename TData>
 inline void LFMCMC<TData>::chrono_start() {
-    time_start = std::chrono::steady_clock::now();
+    m_start_time = std::chrono::steady_clock::now();
 }
 
 template<typename TData>
 inline void LFMCMC<TData>::chrono_end() {
-    time_end = std::chrono::steady_clock::now();
-    time_elapsed += (time_end - time_start);
+    m_end_time = std::chrono::steady_clock::now();
+    m_elapsed_time += (m_end_time - m_start_time);
 }
 
 template<typename TData>
-inline void LFMCMC<TData>::set_par_names(std::vector< std::string > names)
+inline void LFMCMC<TData>::set_params_names(std::vector< std::string > names)
 {
 
-    if (names.size() != n_parameters)
+    if (names.size() != m_n_params)
         throw std::length_error("The number of names to add differs from the number of parameters in the model.");
 
-    names_parameters = names;
+    m_param_names = names;
 
 }
 template<typename TData>
 inline void LFMCMC<TData>::set_stats_names(std::vector< std::string > names)
 {
 
-    if (names.size() != n_statistics)
+    if (names.size() != m_n_stats)
         throw std::length_error("The number of names to add differs from the number of statistics in the model.");
 
-    names_statistics = names;
+    m_stat_names = names;
 
 }
 
 template<typename TData>
-inline std::vector< epiworld_double > LFMCMC<TData>::get_params_mean()
+inline std::vector< epiworld_double > LFMCMC<TData>::get_mean_params()
 {
-    std::vector< epiworld_double > res(this->n_parameters, 0.0);
+    std::vector< epiworld_double > res(this->m_n_params, 0.0);
     
-    for (size_t k = 0u; k < n_parameters; ++k)
+    for (size_t k = 0u; k < m_n_params; ++k)
     {
-        for (size_t i = 0u; i < n_samples; ++i)
-            res[k] += (this->accepted_params[k + n_parameters * i])/
-                static_cast< epiworld_double >(n_samples);
+        for (size_t i = 0u; i < m_n_samples; ++i)
+            res[k] += (this->m_all_accepted_params[k + m_n_params * i])/
+                static_cast< epiworld_double >(m_n_samples);
     }
 
     return res;
@@ -517,19 +549,33 @@ inline std::vector< epiworld_double > LFMCMC<TData>::get_params_mean()
 }
 
 template<typename TData>
-inline std::vector< epiworld_double > LFMCMC<TData>::get_stats_mean()
+inline std::vector< epiworld_double > LFMCMC<TData>::get_mean_stats()
 {
-    std::vector< epiworld_double > res(this->n_statistics, 0.0);
+    std::vector< epiworld_double > res(this->m_n_stats, 0.0);
     
-    for (size_t k = 0u; k < n_statistics; ++k)
+    for (size_t k = 0u; k < m_n_stats; ++k)
     {
-        for (size_t i = 0u; i < n_samples; ++i)
-            res[k] += (this->accepted_stats[k + n_statistics * i])/
-                static_cast< epiworld_double >(n_samples);
+        for (size_t i = 0u; i < m_n_samples; ++i)
+            res[k] += (this->m_all_accepted_stats[k + m_n_stats * i])/
+                static_cast< epiworld_double >(m_n_samples);
     }
 
     return res;
 
 }
 
+template<typename TData>
+inline LFMCMC<TData> & LFMCMC<TData>::verbose_off()
+{
+    verbose = false;
+    return *this;
+}
+
+template<typename TData>
+inline LFMCMC<TData> & LFMCMC<TData>::verbose_on()
+{
+    verbose = true;
+    return *this;
+}
+
 #endif
\ No newline at end of file
diff --git a/include/epiworld/misc.hpp b/include/epiworld/misc.hpp
index dbeb73d..6e0376b 100644
--- a/include/epiworld/misc.hpp
+++ b/include/epiworld/misc.hpp
@@ -124,7 +124,7 @@ inline bool IN(const Ta & a, const std::vector< Ta > & b) noexcept
  * @return int If -1 then it means that none got sampled, otherwise the index
  * of the entry that got drawn.
  */
-template<typename TSeq, typename TDbl>
+template<typename TSeq = EPI_DEFAULT_TSEQ, typename TDbl = epiworld_double >
 inline int roulette(
     const std::vector< TDbl > & probs,
     Model<TSeq> * m
diff --git a/include/epiworld/model-bones.hpp b/include/epiworld/model-bones.hpp
index cf454d4..d405509 100644
--- a/include/epiworld/model-bones.hpp
+++ b/include/epiworld/model-bones.hpp
@@ -140,7 +140,7 @@ class Model {
     std::vector< Entity<TSeq> > entities = {}; 
     std::vector< Entity<TSeq> > entities_backup = {};
 
-    std::mt19937 engine;
+    std::shared_ptr< std::mt19937 > engine = std::make_shared< std::mt19937 >();
     
     std::uniform_real_distribution<> runifd      =
         std::uniform_real_distribution<> (0.0, 1.0);
@@ -286,8 +286,8 @@ class Model {
      * @param s Seed
      */
     ///@{
-    void set_rand_engine(std::mt19937 & eng);
-    std::mt19937 & get_rand_endgine();
+    void set_rand_engine(std::shared_ptr< std::mt19937 > & eng);
+    std::shared_ptr< std::mt19937 > & get_rand_endgine();
     void seed(size_t s);
     void set_rand_norm(epiworld_double mean, epiworld_double sd);
     void set_rand_unif(epiworld_double a, epiworld_double b);
diff --git a/include/epiworld/model-meat.hpp b/include/epiworld/model-meat.hpp
index f04f79d..4916016 100644
--- a/include/epiworld/model-meat.hpp
+++ b/include/epiworld/model-meat.hpp
@@ -674,12 +674,6 @@ inline void Model<TSeq>::agents_empty_graph(
 
 }
 
-// template<typename TSeq>
-// inline void Model<TSeq>::set_rand_engine(std::mt19937 & eng)
-// {
-//     engine = std::make_shared< std::mt19937 >(eng);
-// }
-
 template<typename TSeq>
 inline void Model<TSeq>::set_rand_gamma(epiworld_double alpha, epiworld_double beta)
 {
@@ -720,7 +714,7 @@ template<typename TSeq>
 inline epiworld_double & Model<TSeq>::operator()(std::string pname) {
 
     if (parameters.find(pname) == parameters.end())
-        throw std::range_error("The parameter "+ pname + "is not in the model.");
+        throw std::range_error("The parameter '"+ pname + "' is not in the model.");
 
     return parameters[pname];
 
@@ -820,7 +814,7 @@ inline void Model<TSeq>::set_backup()
 // }
 
 template<typename TSeq>
-inline std::mt19937 & Model<TSeq>::get_rand_endgine()
+inline std::shared_ptr< std::mt19937 > & Model<TSeq>::get_rand_endgine()
 {
     return engine;
 }
@@ -828,86 +822,86 @@ inline std::mt19937 & Model<TSeq>::get_rand_endgine()
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::runif() {
     // CHECK_INIT()
-    return runifd(engine);
+    return runifd(*engine);
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::runif(epiworld_double a, epiworld_double b) {
     // CHECK_INIT()
-    return runifd(engine) * (b - a) + a;
+    return runifd(*engine) * (b - a) + a;
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rnorm() {
     // CHECK_INIT()
-    return rnormd(engine);
+    return rnormd(*engine);
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rnorm(epiworld_double mean, epiworld_double sd) {
     // CHECK_INIT()
-    return rnormd(engine) * sd + mean;
+    return rnormd(*engine) * sd + mean;
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rgamma() {
-    return rgammad(engine);
+    return rgammad(*engine);
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rgamma(epiworld_double alpha, epiworld_double beta) {
     auto old_param = rgammad.param();
     rgammad.param(std::gamma_distribution<>::param_type(alpha, beta));
-    epiworld_double ans = rgammad(engine);
+    epiworld_double ans = rgammad(*engine);
     rgammad.param(old_param);
     return ans;
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rexp() {
-    return rexpd(engine);
+    return rexpd(*engine);
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rexp(epiworld_double lambda) {
     auto old_param = rexpd.param();
     rexpd.param(std::exponential_distribution<>::param_type(lambda));
-    epiworld_double ans = rexpd(engine);
+    epiworld_double ans = rexpd(*engine);
     rexpd.param(old_param);
     return ans;
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rlognormal() {
-    return rlognormald(engine);
+    return rlognormald(*engine);
 }
 
 template<typename TSeq>
 inline epiworld_double Model<TSeq>::rlognormal(epiworld_double mean, epiworld_double shape) {
     auto old_param = rlognormald.param();
     rlognormald.param(std::lognormal_distribution<>::param_type(mean, shape));
-    epiworld_double ans = rlognormald(engine);
+    epiworld_double ans = rlognormald(*engine);
     rlognormald.param(old_param);
     return ans;
 }
 
 template<typename TSeq>
 inline int Model<TSeq>::rbinom() {
-    return rbinomd(engine);
+    return rbinomd(*engine);
 }
 
 template<typename TSeq>
 inline int Model<TSeq>::rbinom(int n, epiworld_double p) {
     auto old_param = rbinomd.param();
     rbinomd.param(std::binomial_distribution<>::param_type(n, p));
-    epiworld_double ans = rbinomd(engine);
+    epiworld_double ans = rbinomd(*engine);
     rbinomd.param(old_param);
     return ans;
 }
 
 template<typename TSeq>
 inline void Model<TSeq>::seed(size_t s) {
-    this->engine.seed(s);
+    this->engine->seed(s);
 }
 
 template<typename TSeq>
@@ -1297,7 +1291,7 @@ inline Model<TSeq> & Model<TSeq>::run(
     this->ndays = ndays;
 
     if (seed >= 0)
-        engine.seed(seed);
+        engine->seed(seed);
 
     array_double_tmp.resize(std::max(
         size(),
diff --git a/include/epiworld/models/surveillance.hpp b/include/epiworld/models/surveillance.hpp
index 6dca7e4..8b1a288 100644
--- a/include/epiworld/models/surveillance.hpp
+++ b/include/epiworld/models/surveillance.hpp
@@ -227,7 +227,7 @@ inline ModelSURV<TSeq>::ModelSURV(
 
         // How many will we find
         std::binomial_distribution<> bdist(m->size(), m->par("Surveilance prob."));
-        int nsampled = bdist(m->get_rand_endgine());
+        int nsampled = bdist(*m->get_rand_endgine());
 
         int to_go = nsampled + 1;
 
diff --git a/include/epiworld/random_graph.hpp b/include/epiworld/random_graph.hpp
index dfe6883..ee13b5f 100644
--- a/include/epiworld/random_graph.hpp
+++ b/include/epiworld/random_graph.hpp
@@ -5,7 +5,7 @@ class RandGraph {
 
 private:
     std::shared_ptr< std::mt19937 > engine;
-    std::shared_ptr< std::uniform_real_distribution<> > unifd;
+    std::uniform_real_distribution<> unifd;
     int N = 0;
     bool initialized = false;
 
@@ -14,7 +14,7 @@ class RandGraph {
     RandGraph(int N_) : N(N_) {};
 
     void init(int s);
-    void set_rand_engine(std::mt19937 & e);
+    void set_rand_engine(std::shared_ptr< std::mt19937 > & e);
     epiworld_double runif();
 
 };
@@ -27,18 +27,15 @@ inline void RandGraph::init(int s) {
 
     engine->seed(s);
 
-    if (!unifd)
-        unifd = std::make_shared< std::uniform_real_distribution<> >(0, 1);
-
     initialized = true;
 
 
 }
 
-inline void RandGraph::set_rand_engine(std::mt19937 & e)
+inline void RandGraph::set_rand_engine(std::shared_ptr< std::mt19937 > & e)
 {
 
-    engine = std::make_shared< std::mt19937 >(e);
+    engine = e;
 
 }
 
@@ -47,7 +44,7 @@ inline epiworld_double RandGraph::runif() {
     if (!initialized)
         throw std::logic_error("The object has not been initialized");
 
-    return (*unifd)(engine);
+    return unifd(*engine);
 
 }