progress
parent
263bde65fb
commit
2b25d61dfb
|
@ -3,4 +3,5 @@
|
||||||
!*.cpp
|
!*.cpp
|
||||||
!*.hpp
|
!*.hpp
|
||||||
!include/
|
!include/
|
||||||
|
!scripts/
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
"deque": "cpp",
|
"deque": "cpp",
|
||||||
"fstream": "cpp",
|
"fstream": "cpp",
|
||||||
"iomanip": "cpp",
|
"iomanip": "cpp",
|
||||||
"stack": "cpp"
|
"stack": "cpp",
|
||||||
|
"numeric": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(test_econ_model)
|
project(test_econ_model)
|
||||||
# set(models "fixed-simple, lending, pop-simple")
|
# set(models "fixed-simple, lending, pop-simple")
|
||||||
# foreach(model models)
|
# foreach(model models)
|
||||||
|
@ -5,6 +6,6 @@ project(test_econ_model)
|
||||||
# endforeach()
|
# endforeach()
|
||||||
make_directory(bin)
|
make_directory(bin)
|
||||||
include_directories(include/)
|
include_directories(include/)
|
||||||
add_executable(./bin/fixed-simple fixed-simple.cpp)
|
add_executable(pop-simple pop-simple.cpp)
|
||||||
add_executable(./bin/wealth-flow wealth-flow.cpp)
|
# add_executable(./bin/fixed-simple fixed-simple.cpp)
|
||||||
add_executable(./bin/pop-simple pop-simple.cpp)
|
# add_executable(./bin/wealth-flow wealth-flow.cpp)
|
||||||
|
|
|
@ -1,12 +1,32 @@
|
||||||
#include<iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
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<int> &balances, int id, float spend_ratio) {
|
void economic_decision_simple(std::vector<int> &balances, int id, float spend_ratio) {
|
||||||
// assert(spend_ratio > 0 && spend_ratio <= 1);
|
// assert(spend_ratio > 0 && spend_ratio <= 1);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
int total_bal = balances.at(id);
|
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<std::mt19937::result_type> dist_spend_ratios(0,10000 * spend_ratio);
|
||||||
|
std::uniform_int_distribution<std::mt19937::result_type> 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(id) -= spendable;
|
||||||
balances.at(recipient_id) += spendable;
|
balances.at(recipient_id) += spendable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void economic_decision_tiered(std::vector<int> &balances, int id, float spend_ratio) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -16,14 +16,13 @@ void dump_balances_csv(std::vector<int> balances, std::string name) {
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dump_balances_and_ages_csv(std::vector<int> balances, std::vector<int> ages, std::string name) {
|
void dump_balances_and_ages_csv(std::vector<int> balances, std::vector<int> ages, std::string name) {
|
||||||
assert(balances.size() == ages.size());
|
assert(balances.size() == ages.size());
|
||||||
std::string csv_data = "Id,Balance,Age\n";
|
std::string csv_data = "Id,Balance,Age\n";
|
||||||
for (int i = 0; i < balances.size(); i++) {
|
for (int i = 0; i < balances.size(); i++) {
|
||||||
csv_data += std::to_string(i+1)+ "," +
|
csv_data += std::to_string(i+1)+ "," +
|
||||||
std::to_string(ages[i]) + "," +
|
std::to_string(balances[i]) + "," +
|
||||||
std::to_string(balances[i]) + "\n";
|
std::to_string(ages[i]) + "\n";
|
||||||
}
|
}
|
||||||
std::ofstream file;
|
std::ofstream file;
|
||||||
file.open(name + ".csv");
|
file.open(name + ".csv");
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
std::random_device util_dev;
|
||||||
|
std::mt19937 util_rng(util_dev());
|
||||||
|
|
||||||
|
int random_item(std::vector<int> items, bool get_id) {
|
||||||
|
std::uniform_int_distribution<std::mt19937::result_type> dist_len(0,items.size()-1);
|
||||||
|
int id = dist_len(util_rng);
|
||||||
|
return get_id ? id : items[id];
|
||||||
|
}
|
129
pop-simple.cpp
129
pop-simple.cpp
|
@ -1,59 +1,90 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "econ.hpp"
|
#include "econ.hpp"
|
||||||
#include "io.hpp"
|
#include "io.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
|
|
||||||
|
std::map<std::string, std::string> 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<int> ages;
|
std::vector<int> ages;
|
||||||
std::vector<int> balances;
|
std::vector<int> balances;
|
||||||
|
|
||||||
const int N_o = 10;
|
enum estate_mode {
|
||||||
const int N = 10000;
|
EVEN_REDIST,
|
||||||
const int DURATION = 1000;
|
INHERITANCE
|
||||||
const int MAX_AGE = 100;
|
};
|
||||||
|
|
||||||
const int STARTING_BALANCE=50000;
|
// used by kill_even_redist
|
||||||
|
|
||||||
const int LOGISTIC_CARRYING_CAPACITY = 100000;
|
int redist_total = 0;
|
||||||
const float LOGISTIC_GROWTH_RATE = 0.04;
|
int redist_total_next = 0;
|
||||||
const int LOGISTIC_MIDPOINT = DURATION / 2;
|
|
||||||
|
|
||||||
// pop modeling functions
|
// 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) {
|
void kill_even_redist(int id) {
|
||||||
int bal = balances.at(id);
|
int bal = balances.at(id);
|
||||||
ages.erase(ages.begin()+id);
|
ages.erase(ages.begin()+id);
|
||||||
balances.erase(balances.begin()+id);
|
balances.erase(balances.begin()+id);
|
||||||
int alloc_each = bal / balances.size();
|
redist_total_next += bal;
|
||||||
for (int i = 0; i < balances.size(); i++) {
|
|
||||||
balances.at(i) += alloc_each;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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) {
|
void kill_inheritance(int id) {
|
||||||
int bal = balances.at(id);
|
int bal = balances.at(id);
|
||||||
ages.erase(ages.begin()+id);
|
ages.erase(ages.begin()+id);
|
||||||
balances.erase(balances.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;
|
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++) {
|
for (int i = 0; i < ages.size(); i++) {
|
||||||
ages.at(i) += 1;
|
ages.at(i) += 1;
|
||||||
if (ages.at(i) > MAX_AGE) {
|
if (ages.at(i) > ci("MAX_AGE")) {
|
||||||
// kill_inheritance(i);
|
switch (mode) {
|
||||||
|
case INHERITANCE:
|
||||||
|
kill_inheritance(i);
|
||||||
|
break;
|
||||||
|
case EVEN_REDIST:
|
||||||
kill_even_redist(i);
|
kill_even_redist(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int logistic_population_func(int year) {
|
int logistic_population_func(int year) {
|
||||||
// https://en.wikipedia.org//wiki/Logistic_function
|
// https://en.wikipedia.org//wiki/Logistic_function
|
||||||
return (LOGISTIC_CARRYING_CAPACITY /
|
return ci("N_o") + (ci("N_f") - ci("N_o")) /
|
||||||
(1 + exp(-LOGISTIC_GROWTH_RATE * (year - LOGISTIC_MIDPOINT))));
|
(1 + exp(-cf("GROWTH_RATE") * (year - ci("DURATION")/2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void adjust_population(int year) {
|
void adjust_population(int year) {
|
||||||
|
@ -61,22 +92,66 @@ void adjust_population(int year) {
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
for (int i = 0; i < diff; i++) {
|
for (int i = 0; i < diff; i++) {
|
||||||
ages.push_back(1);
|
ages.push_back(1);
|
||||||
balances.push_back(0);
|
balances.push_back(ci("STARTING_BALANCE_NEW"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// init state
|
// set config
|
||||||
ages.assign(N_o, 1);
|
|
||||||
balances.assign(N_o, STARTING_BALANCE);
|
|
||||||
|
|
||||||
for (int year = 0; year < DURATION; year++) {
|
// model params
|
||||||
age_all();
|
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);
|
adjust_population(year);
|
||||||
// for (int j = 0; j < balances.size(); j++) {
|
for (int j = 0; j < balances.size(); j++) {
|
||||||
// economic_decision_simple(balances, j, 0.4);
|
// 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<int>());
|
// std::sort(balances.begin(), balances.end(), std::greater<int>());
|
||||||
|
|
Loading…
Reference in New Issue