// model with logistic population growth & basic // inflation + estate redistribution systems #include #include #include #include #include #include #include "econ.hpp" #include "io.hpp" #include "util.hpp" std::map config; #define c(a) config[a] #define ci(a) std::stoi(config[a]) #define cf(a) std::stof(config[a]) #define csets(k, v) config[k] = v #define csetn(k, v) config[k] = std::to_string(v); std::vector ages; std::vector balances; enum estate_mode { EVEN_REDIST, INHERITANCE }; // used by kill_even_redist int redist_total = 0; int redist_total_next = 0; // pop modeling functions /** * @brief kill participant of ID and redistribute their wealth * to all other remaining participants evenly * * @param id ID of participant to kill */ void kill_even_redist(int id) { int bal = balances.at(id); ages.erase(ages.begin()+id); balances.erase(balances.begin()+id); redist_total_next += bal; } /** * @brief kill participant of ID and give it to one random * participant as inheritance * * @param id ID of participant to kill */ void kill_inheritance(int id) { int bal = balances.at(id); ages.erase(ages.begin()+id); balances.erase(balances.begin()+id); int recipient_id = random_item(balances, true); balances.at(recipient_id) += bal; } /** * @brief Age all participants by 1 year & kill any that are * over the age limit * * @param mode Redistribution mode */ void age_all(estate_mode mode) { for (int i = 0; i < ages.size(); i++) { ages.at(i) += 1; if (ages.at(i) > ci("MAX_AGE")) { switch (mode) { case INHERITANCE: kill_inheritance(i); break; case EVEN_REDIST: kill_even_redist(i); break; } } } } int logistic_population_func(int year) { // https://en.wikipedia.org//wiki/Logistic_function return ci("N_o") + (ci("N_f") - ci("N_o")) / (1 + exp(-cf("GROWTH_RATE") * (year - ci("DURATION")/2))); } void adjust_population(int year) { int diff = logistic_population_func(year) - balances.size(); if (diff > 0) { for (int i = 0; i < diff; i++) { ages.push_back(1); balances.push_back(ci("STARTING_BALANCE_NEW")); } } } int main() { // set config - make configurable with params later // model params csetn("DURATION", 1000); csetn("MAX_AGE", 81); csetn("INIT_BALANCE_EACH", 5000); csetn("STARTING_BALANCE_NEW", 1000); // effectively inflation rate // logistic growth params csetn("N_o", 10); csetn("N_f", 10000); csetn("GROWTH_RATE", 0.04); // init state ages.assign(ci("N_o"), 1); balances.assign(ci("N_o"), ci("INIT_BALANCE_EACH")); // estate mode // estate_mode emode = INHERITANCE; estate_mode emode = EVEN_REDIST; for (int year = 0; year < ci("DURATION"); year++) { // std::cout << year << "\t" << balances.size() << std::endl; age_all(emode); adjust_population(year); for (int j = 0; j < balances.size(); j++) { // redistribute estates balances.at(j) += redist_total / balances.size(); // make 3 arbitrary spending decisions -> 30% of savings for (int k = 0; k < 3; k++) { economic_decision_simple(balances, j, 0.1); } } if (year % 100 == 0) { int avg = 0; int avg_age = 0; for (int i = 0; i < balances.size(); i++) { avg += balances[i]; } for (int i = 0; i < balances.size(); i++) { avg_age += ages[i]; } avg /= balances.size(); avg_age /= ages.size(); std::cout << std::endl; std::cout << "year: " << year << std::endl; std::cout << "avg bal: " << avg << std::endl; std::cout << "avg age: " << avg_age << std::endl; std::cout << "players: " << balances.size() << std::endl; } // reset redist tally redist_total = redist_total_next; redist_total_next = 0; } // std::sort(balances.begin(), balances.end(), std::greater()); dump_balances_and_ages_csv(balances, ages, "pop-balances-out"); std::cout << "Finished with " << balances.size() << " balances\n"; return 0; }