| Signature | Description | Parameters |
|---|---|---|
template<typename T> std::vector<scalar_t<T>> MC_station_dist(std::vector<const char *> &&col_names, bool build_trans_cols = true, size_type bins = 0, size_type max_iter = 1000, double epsilon = double(1e-8)) const; |
Markov Chains Stationary Distributions A stationary distribution in the context of Markov Chains refers to a probability distribution that remains unchanged over time, meaning if a Markov chain starts in this distribution, it will always stay in that same distribution regardless of how many steps are taken; essentially, it represents a stable state of the chain where the probabilities of being in each state do not fluctuate further. In probability theory and statistics, a Markov chain or Markov process is a stochastic process describing a sequence of possible events in which the probability of each event depends only on the state attained in the previous event. Informally, this may be thought of as; What happens next depends only on the state of affairs now. Return result is always a vector of scalar values. Every entry in the vector is a decimal or fraction between 0 and 1, representing the proportion of time (percentage) the system will spend in that particular state in the long run. It should sum up to 1.0 This works with both scalar and multidimensional (MD), vectors and arrays, data. Return result is always a vector of scalar values. NOTE: This method solves the problem iteratively. If the returned vector is empty, it means the algorithm did not converge. NOTE: If you are providing the transition columns (build_trans_cols==false), the type T must be scalar. |
T: Type of the named columns col_names: Names of the DataFrame columns. Depending on build_trans_cols, they are either raw columns or transition columns of the transition matrix build_trans_cols: If true, it means the input columns are raw data columns and they should be converted to transition columns. If false, it means they are already transition columns. bins: A Markov Chain stationary distribution requires defining states and transition probabilities between states. State is straightforward, discretize data into bins. This is only relevant if build_trans_cols==true. Your options are:
epsilon: Threshold for convergence |
static void test_MC_station_dist() { std::cout << "\nTesting MC_station_dist( ) ..." << std::endl; const std::size_t item_cnt = 20; MyDataFrame df; df.load_index(MyDataFrame::gen_sequence_index(0, item_cnt, 1)); RandGenParams<double> p; std::vector<const char *> col_names (item_cnt, nullptr); p.seed = 16; df.load_column("0_col_name", gen_normal_dist<double, 256>(item_cnt, p)); for (std::size_t i = 1; i < item_cnt; ++i) { p.seed = i; df.load_column((std::to_string(i) + "_col_name").c_str(), gen_normal_dist<double, 256>(item_cnt, p)); } for (std::size_t i = 0; i < item_cnt; ++i) col_names[i] = df.col_idx_to_name(i); // This call with raw columns as input to the process makes no sense. I am // calling it here as an anchor for calculation results. // const auto result1 = df.MC_station_dist<double>(std::forward<std::vector<const char *>>(col_names), false); assert(result1.size() == 20); assert(std::fabs(result1[0] - -0.45676) < 0.000001); assert(std::fabs(result1[5] - -0.0338666) < 0.000001); assert(std::fabs(result1[15] - -0.10117) < 0.000001); assert(std::fabs(result1[19] - 0.232359) < 0.000001); // This is the correct way of calling it which returns the results that // make sense. // const auto result2 = df.MC_station_dist<double>(std::forward<std::vector<const char *>>(col_names), true); assert(result2.size() == 6); assert(std::fabs(result2[0] - 0.182232) < 0.000001); assert(std::fabs(result2[2] - 0.145786) < 0.000001); assert(std::fabs(result2[4] - 0.255125) < 0.000001); assert(std::fabs(result2[5] - 0.143508) < 0.000001); // Now multidimensional data // constexpr std::size_t dim { 2 }; using ary_col_t = std::array<double, dim>; using vec_col_t = std::vector<double>; const std::size_t item_cnt2 = 256; MyDataFrame df2; df2.load_index(MyDataFrame::gen_sequence_index(0, item_cnt2, 1)); StlVecType<ary_col_t> md_ary_col1 { // Regime A: bottom-left (~[-2,-2]) {-2.1, -1.8}, {-1.9, -2.0}, {-2.3, -1.7}, {-1.8, -2.1}, {-2.0, -1.9}, {-2.2, -2.0}, {-1.7, -1.8}, {-2.1, -2.2}, {-1.9, -1.7}, {-2.0, -2.0}, {-2.1, -1.9}, {-1.8, -2.1}, {-2.3, -1.8}, {-2.0, -2.2}, {-1.9, -1.9}, {-2.2, -1.7}, {-2.0, -2.0}, {-1.8, -1.9}, {-2.1, -2.1}, {-2.0, -1.8}, {-1.9, -2.0}, {-2.1, -1.8}, {-2.0, -2.1}, {-1.8, -1.9}, {-2.2, -2.0}, {-2.0, -1.8}, {-1.9, -2.2}, {-2.1, -1.9}, {-2.0, -2.0}, {-1.8, -2.1}, {-2.2, -1.7}, {-2.0, -2.3}, {-1.9, -1.8}, {-2.1, -2.0}, {-2.0, -1.9}, {-2.0, -2.1}, {-1.9, -1.8}, {-2.1, -2.0}, {-2.0, -1.9}, {-1.8, -2.2}, {-2.2, -2.0}, {-2.0, -1.7}, {-1.9, -2.1}, {-2.1, -1.9}, {-2.0, -2.0}, {-1.8, -1.9}, {-2.1, -2.1}, {-2.0, -2.0}, {-2.2, -1.8}, {-1.9, -2.0}, {-2.1, -2.0}, {-2.0, -1.9}, {-1.9, -2.1}, {-2.2, -2.0}, {-1.8, -1.9}, {-2.0, -2.1}, {-2.1, -1.8}, {-1.9, -2.0}, {-2.0, -2.2}, {-2.2, -1.9}, {-1.8, -2.0}, {-2.1, -2.1}, {-2.0, -1.8}, {-1.9, -1.9}, {-2.1, -2.0}, {-2.0, -2.0}, {-1.8, -2.1}, {-2.2, -1.9}, {-2.0, -2.0}, {-1.9, -1.8}, {-2.0, -1.9}, {-2.1, -2.1}, {-1.9, -2.0}, {-2.0, -1.8}, {-1.8, -2.1}, {-2.2, -2.0}, {-2.0, -2.1}, {-1.9, -1.9}, {-2.1, -2.0}, {-2.0, -2.2}, // Transition A→C {-0.2, 0.1}, {-0.1, -0.2}, {0.1, 0.0}, {-0.2, 0.2}, {0.0, -0.1}, // Regime C: center (~[0,0]) {0.0, 0.1}, {0.1, -0.1}, {-0.1, 0.2}, {0.2, 0.0}, {-0.1, -0.2}, {0.1, 0.2}, {-0.2, -0.1}, {0.0, 0.1}, {0.2, -0.1}, {-0.1, 0.0}, {0.0, 0.0}, {0.2, 0.1}, {-0.1, 0.2}, {0.1, -0.2}, { 0.0, 0.1}, {-0.1, 0.1}, {0.2, 0.0}, {0.0, -0.2}, {-0.1, 0.1}, {0.1, 0.2}, {0.0, 0.1}, {-0.1, -0.2}, {0.2, 0.0}, {0.1, 0.1}, {-0.2, 0.2}, {0.1, -0.1}, {0.0, 0.2}, {-0.2, 0.0}, {0.1, 0.1}, {-0.1, -0.2}, {-0.2, 0.1}, {0.0, -0.1}, {0.1, 0.2}, {-0.1, 0.0}, {0.2, -0.1}, // Transition C→B {0.1, 0.2}, {0.2, 0.1}, {0.3, 0.3}, {0.5, 0.5}, {1.0, 1.0}, // Regime B: top-right (~[2,2]) {2.1, 1.9}, {1.9, 2.1}, {2.0, 2.0}, {2.2, 1.8}, {1.8, 2.2}, {2.0, 2.1}, {2.1, 1.8}, {1.9, 2.0}, {2.2, 2.1}, {2.0, 1.9}, {2.1, 2.0}, {1.8, 2.1}, {2.0, 2.2}, {1.9, 1.9}, {2.2, 2.0}, {2.0, 1.8}, {2.1, 2.1}, {1.9, 2.0}, {2.0, 2.2}, {1.8, 1.9}, {2.0, 2.0}, {2.2, 1.9}, {1.9, 2.1}, {2.1, 2.0}, {2.0, 1.8}, {1.8, 2.0}, {2.1, 2.2}, {2.0, 1.9}, {1.9, 2.1}, {2.2, 2.0}, {2.0, 2.1}, {1.9, 1.8}, {2.1, 2.0}, {2.0, 2.2}, {1.8, 2.1}, {2.0, 2.0}, {2.2, 2.1}, {1.9, 1.8}, {2.1, 2.2}, {2.0, 1.9}, {1.8, 2.1}, {2.2, 2.0}, {2.0, 1.9}, {2.1, 2.1}, {1.9, 2.0}, {2.0, 2.1}, {1.9, 2.0}, {2.1, 1.9}, {2.0, 2.2}, {1.8, 2.0}, {2.1, 2.0}, {2.0, 1.9}, {1.8, 2.1}, {2.2, 2.0}, {1.9, 2.2}, {2.0, 2.0}, {2.1, 2.2}, {1.9, 1.9}, {2.0, 2.1}, {1.8, 2.0}, {2.2, 2.1}, {2.0, 1.8}, {1.9, 2.0}, {2.1, 1.9}, {2.0, 2.1}, {1.8, 2.2}, {2.1, 1.9}, {2.0, 2.1}, {1.9, 2.0}, {2.2, 1.8}, {2.0, 2.0}, {2.1, 2.1}, {1.9, 2.0}, {2.2, 1.9}, {1.8, 2.1}, {2.0, 1.9}, {2.1, 2.0}, {1.9, 2.2}, {2.0, 2.1}, {1.8, 1.9}, // Transition B→A (loop back) {1.0, 1.0}, {0.5, 0.5}, {0.0, 0.0}, {-0.5, -0.5}, {-1.0, -1.0} }; StlVecType<vec_col_t> md_vec_col1 { // Regime A: bottom-left (~[-2,-2]) {-2.1, -1.8}, {-1.9, -2.0}, {-2.3, -1.7}, {-1.8, -2.1}, {-2.0, -1.9}, {-2.2, -2.0}, {-1.7, -1.8}, {-2.1, -2.2}, {-1.9, -1.7}, {-2.0, -2.0}, {-2.1, -1.9}, {-1.8, -2.1}, {-2.3, -1.8}, {-2.0, -2.2}, {-1.9, -1.9}, {-2.2, -1.7}, {-2.0, -2.0}, {-1.8, -1.9}, {-2.1, -2.1}, {-2.0, -1.8}, {-1.9, -2.0}, {-2.1, -1.8}, {-2.0, -2.1}, {-1.8, -1.9}, {-2.2, -2.0}, {-2.0, -1.8}, {-1.9, -2.2}, {-2.1, -1.9}, {-2.0, -2.0}, {-1.8, -2.1}, {-2.2, -1.7}, {-2.0, -2.3}, {-1.9, -1.8}, {-2.1, -2.0}, {-2.0, -1.9}, {-2.0, -2.1}, {-1.9, -1.8}, {-2.1, -2.0}, {-2.0, -1.9}, {-1.8, -2.2}, {-2.2, -2.0}, {-2.0, -1.7}, {-1.9, -2.1}, {-2.1, -1.9}, {-2.0, -2.0}, {-1.8, -1.9}, {-2.1, -2.1}, {-2.0, -2.0}, {-2.2, -1.8}, {-1.9, -2.0}, {-2.1, -2.0}, {-2.0, -1.9}, {-1.9, -2.1}, {-2.2, -2.0}, {-1.8, -1.9}, {-2.0, -2.1}, {-2.1, -1.8}, {-1.9, -2.0}, {-2.0, -2.2}, {-2.2, -1.9}, {-1.8, -2.0}, {-2.1, -2.1}, {-2.0, -1.8}, {-1.9, -1.9}, {-2.1, -2.0}, {-2.0, -2.0}, {-1.8, -2.1}, {-2.2, -1.9}, {-2.0, -2.0}, {-1.9, -1.8}, {-2.0, -1.9}, {-2.1, -2.1}, {-1.9, -2.0}, {-2.0, -1.8}, {-1.8, -2.1}, {-2.2, -2.0}, {-2.0, -2.1}, {-1.9, -1.9}, {-2.1, -2.0}, {-2.0, -2.2}, // Transition A→C {-0.2, 0.1}, {-0.1, -0.2}, {0.1, 0.0}, {-0.2, 0.2}, {0.0, -0.1}, // Regime C: center (~[0,0]) {0.0, 0.1}, {0.1, -0.1}, {-0.1, 0.2}, {0.2, 0.0}, {-0.1, -0.2}, {0.1, 0.2}, {-0.2, -0.1}, {0.0, 0.1}, {0.2, -0.1}, {-0.1, 0.0}, {0.0, 0.0}, {0.2, 0.1}, {-0.1, 0.2}, {0.1, -0.2}, { 0.0, 0.1}, {-0.1, 0.1}, {0.2, 0.0}, {0.0, -0.2}, {-0.1, 0.1}, {0.1, 0.2}, {0.0, 0.1}, {-0.1, -0.2}, {0.2, 0.0}, {0.1, 0.1}, {-0.2, 0.2}, {0.1, -0.1}, {0.0, 0.2}, {-0.2, 0.0}, {0.1, 0.1}, {-0.1, -0.2}, {-0.2, 0.1}, {0.0, -0.1}, {0.1, 0.2}, {-0.1, 0.0}, {0.2, -0.1}, // Transition C→B {0.1, 0.2}, {0.2, 0.1}, {0.3, 0.3}, {0.5, 0.5}, {1.0, 1.0}, // Regime B: top-right (~[2,2]) {2.1, 1.9}, {1.9, 2.1}, {2.0, 2.0}, {2.2, 1.8}, {1.8, 2.2}, {2.0, 2.1}, {2.1, 1.8}, {1.9, 2.0}, {2.2, 2.1}, {2.0, 1.9}, {2.1, 2.0}, {1.8, 2.1}, {2.0, 2.2}, {1.9, 1.9}, {2.2, 2.0}, {2.0, 1.8}, {2.1, 2.1}, {1.9, 2.0}, {2.0, 2.2}, {1.8, 1.9}, {2.0, 2.0}, {2.2, 1.9}, {1.9, 2.1}, {2.1, 2.0}, {2.0, 1.8}, {1.8, 2.0}, {2.1, 2.2}, {2.0, 1.9}, {1.9, 2.1}, {2.2, 2.0}, {2.0, 2.1}, {1.9, 1.8}, {2.1, 2.0}, {2.0, 2.2}, {1.8, 2.1}, {2.0, 2.0}, {2.2, 2.1}, {1.9, 1.8}, {2.1, 2.2}, {2.0, 1.9}, {1.8, 2.1}, {2.2, 2.0}, {2.0, 1.9}, {2.1, 2.1}, {1.9, 2.0}, {2.0, 2.1}, {1.9, 2.0}, {2.1, 1.9}, {2.0, 2.2}, {1.8, 2.0}, {2.1, 2.0}, {2.0, 1.9}, {1.8, 2.1}, {2.2, 2.0}, {1.9, 2.2}, {2.0, 2.0}, {2.1, 2.2}, {1.9, 1.9}, {2.0, 2.1}, {1.8, 2.0}, {2.2, 2.1}, {2.0, 1.8}, {1.9, 2.0}, {2.1, 1.9}, {2.0, 2.1}, {1.8, 2.2}, {2.1, 1.9}, {2.0, 2.1}, {1.9, 2.0}, {2.2, 1.8}, {2.0, 2.0}, {2.1, 2.1}, {1.9, 2.0}, {2.2, 1.9}, {1.8, 2.1}, {2.0, 1.9}, {2.1, 2.0}, {1.9, 2.2}, {2.0, 2.1}, {1.8, 1.9}, // Transition B→A (loop back) {1.0, 1.0}, {0.5, 0.5}, {0.0, 0.0}, {-0.5, -0.5}, {-1.0, -1.0} }; df2.load_column<ary_col_t>("ARY COL 1", std::move(md_ary_col1), nan_policy::dont_pad_with_nans); df2.load_column<vec_col_t>("VEC COL 1", std::move(md_vec_col1), nan_policy::dont_pad_with_nans); const auto ary_res = df2.MC_station_dist<ary_col_t>({ "ARY COL 1" }, true); const auto vec_res = df2.MC_station_dist<vec_col_t>({ "VEC COL 1" }, true); assert(ary_res.size() == 16); assert(vec_res.size() == 16); assert(std::fabs(ary_res[0] - 0.196076) < 0.000001); assert(std::fabs(ary_res[4] - 0.034722) < 0.000001); assert(std::fabs(ary_res[11] - 0.034722) < 0.000001); assert(std::fabs(ary_res[15] - 0.208413) < 0.000001); assert(std::fabs(vec_res[0] - 0.196076) < 0.000001); assert(std::fabs(vec_res[4] - 0.034722) < 0.000001); assert(std::fabs(vec_res[11] - 0.034722) < 0.000001); assert(std::fabs(vec_res[15] - 0.208413) < 0.000001); }