From 2b25d61dfbc78555e74c5dda3b79a6e14738301e Mon Sep 17 00:00:00 2001 From: turtlebasket Date: Thu, 1 Dec 2022 05:59:32 +0800 Subject: [PATCH] progress --- .gitignore | 1 + .vscode/settings.json | 3 +- CMakeLists.txt | 7 ++- include/econ.hpp | 28 +++++++-- include/io.hpp | 5 +- include/util.hpp | 12 ++++ pop-simple.cpp | 131 +++++++++++++++++++++++++++++++++--------- 7 files changed, 148 insertions(+), 39 deletions(-) create mode 100644 include/util.hpp diff --git a/.gitignore b/.gitignore index 4e7d853..7fffea6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ !*.cpp !*.hpp !include/ +!scripts/ !.gitignore diff --git a/.vscode/settings.json b/.vscode/settings.json index ac00b4c..66f0410 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,6 +59,7 @@ "deque": "cpp", "fstream": "cpp", "iomanip": "cpp", - "stack": "cpp" + "stack": "cpp", + "numeric": "cpp" } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 287b8c2..11f90ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,4 @@ +cmake_minimum_required(VERSION 3.25) project(test_econ_model) # set(models "fixed-simple, lending, pop-simple") # foreach(model models) @@ -5,6 +6,6 @@ project(test_econ_model) # endforeach() make_directory(bin) include_directories(include/) -add_executable(./bin/fixed-simple fixed-simple.cpp) -add_executable(./bin/wealth-flow wealth-flow.cpp) -add_executable(./bin/pop-simple pop-simple.cpp) +add_executable(pop-simple pop-simple.cpp) +# add_executable(./bin/fixed-simple fixed-simple.cpp) +# add_executable(./bin/wealth-flow wealth-flow.cpp) diff --git a/include/econ.hpp b/include/econ.hpp index cd65df7..9316ca2 100644 --- a/include/econ.hpp +++ b/include/econ.hpp @@ -1,12 +1,32 @@ -#include +#include #include +#include +std::random_device econ_dev; +std::mt19937 econ_rng(econ_dev()); + +/** + * @brief Simple random economic spend decision + * + * @param balances Balances vec + * @param id ID of participant making the decision + * @param spend_ratio Proportion of savings they are willing + * to spend + */ void economic_decision_simple(std::vector &balances, int id, float spend_ratio) { // assert(spend_ratio > 0 && spend_ratio <= 1); - std::cout << "test" << std::endl; int total_bal = balances.at(id); - int spendable = (random() * spend_ratio) * total_bal; - int recipient_id = random() * (balances.size()); + + // random spend ratio is too costly + // std::uniform_int_distribution dist_spend_ratios(0,10000 * spend_ratio); + std::uniform_int_distribution dist_len(0,balances.size()-1); + + int spendable = spend_ratio * total_bal; + int recipient_id = dist_len(econ_rng); balances.at(id) -= spendable; balances.at(recipient_id) += spendable; } + +void economic_decision_tiered(std::vector &balances, int id, float spend_ratio) { + +} diff --git a/include/io.hpp b/include/io.hpp index 344bbb2..7127bfa 100644 --- a/include/io.hpp +++ b/include/io.hpp @@ -16,14 +16,13 @@ void dump_balances_csv(std::vector balances, std::string name) { file.close(); } - void dump_balances_and_ages_csv(std::vector balances, std::vector ages, std::string name) { assert(balances.size() == ages.size()); std::string csv_data = "Id,Balance,Age\n"; for (int i = 0; i < balances.size(); i++) { csv_data += std::to_string(i+1)+ "," + - std::to_string(ages[i]) + "," + - std::to_string(balances[i]) + "\n"; + std::to_string(balances[i]) + "," + + std::to_string(ages[i]) + "\n"; } std::ofstream file; file.open(name + ".csv"); diff --git a/include/util.hpp b/include/util.hpp new file mode 100644 index 0000000..3dbfe8c --- /dev/null +++ b/include/util.hpp @@ -0,0 +1,12 @@ +#include +#include +#include + +std::random_device util_dev; +std::mt19937 util_rng(util_dev()); + +int random_item(std::vector items, bool get_id) { + std::uniform_int_distribution dist_len(0,items.size()-1); + int id = dist_len(util_rng); + return get_id ? id : items[id]; +} diff --git a/pop-simple.cpp b/pop-simple.cpp index e485612..105d99d 100644 --- a/pop-simple.cpp +++ b/pop-simple.cpp @@ -1,59 +1,90 @@ #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; -const int N_o = 10; -const int N = 10000; -const int DURATION = 1000; -const int MAX_AGE = 100; +enum estate_mode { + EVEN_REDIST, + INHERITANCE +}; -const int STARTING_BALANCE=50000; +// used by kill_even_redist -const int LOGISTIC_CARRYING_CAPACITY = 100000; -const float LOGISTIC_GROWTH_RATE = 0.04; -const int LOGISTIC_MIDPOINT = DURATION / 2; +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); - int alloc_each = bal / balances.size(); - for (int i = 0; i < balances.size(); i++) { - balances.at(i) += alloc_each; - } + 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 = (balances.size() - 1) * random(); + int recipient_id = random_item(balances, true); balances.at(recipient_id) += bal; } -void age_all() { +/** + * @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) > MAX_AGE) { - // kill_inheritance(i); - kill_even_redist(i); + 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 (LOGISTIC_CARRYING_CAPACITY / - (1 + exp(-LOGISTIC_GROWTH_RATE * (year - LOGISTIC_MIDPOINT)))); + return ci("N_o") + (ci("N_f") - ci("N_o")) / + (1 + exp(-cf("GROWTH_RATE") * (year - ci("DURATION")/2))); } void adjust_population(int year) { @@ -61,22 +92,66 @@ void adjust_population(int year) { if (diff > 0) { for (int i = 0; i < diff; i++) { ages.push_back(1); - balances.push_back(0); + balances.push_back(ci("STARTING_BALANCE_NEW")); } } } int main() { - // init state - ages.assign(N_o, 1); - balances.assign(N_o, STARTING_BALANCE); + // set config - for (int year = 0; year < DURATION; year++) { - age_all(); + // 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 = 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++) { - // economic_decision_simple(balances, j, 0.4); - // } + 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); + } + } + // std::cout << redist_total << " distributed\n"; + + 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());