Skip to content

Commit ff25f62

Browse files
authored
Merge pull request #614 from OpenVicProject/randomise_artisan_switching
Randomise artisan switching
2 parents 624e2f8 + 18575d2 commit ff25f62

File tree

9 files changed

+170
-73
lines changed

9 files changed

+170
-73
lines changed

src/openvic-simulation/economy/production/ArtisanalProducer.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
#include "openvic-simulation/pop/Pop.hpp"
1313
#include "openvic-simulation/pop/PopValuesFromProvince.hpp"
1414
#include "openvic-simulation/types/fixed_point/FixedPoint.hpp"
15+
#include "openvic-simulation/utility/RandomGenerator.hpp"
1516
#include "openvic-simulation/utility/Typedefs.hpp"
17+
#include "openvic-simulation/utility/WeightedSampling.hpp"
1618

1719
using namespace OpenVic;
1820

@@ -47,14 +49,21 @@ void ArtisanalProducer::set_production_type(ProductionType const* const new_prod
4749
void ArtisanalProducer::artisan_tick(
4850
Pop& pop,
4951
PopValuesFromProvince const& values_from_province,
52+
RandomU32& random_number_generator,
5053
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
5154
memory::vector<fixed_point_t>& pop_max_quantity_to_buy_per_good,
5255
memory::vector<fixed_point_t>& pop_money_to_spend_per_good,
5356
memory::vector<fixed_point_t>& reusable_map_0,
5457
memory::vector<fixed_point_t>& reusable_map_1
5558
) {
5659
ProductionType const* const old_production_type = production_type_nullable;
57-
set_production_type(pick_production_type(pop, values_from_province));
60+
set_production_type(
61+
pick_production_type(
62+
pop,
63+
values_from_province,
64+
random_number_generator
65+
)
66+
);
5867
if (production_type_nullable == nullptr) {
5968
return;
6069
}
@@ -344,7 +353,8 @@ fixed_point_t ArtisanalProducer::calculate_production_type_score(
344353

345354
ProductionType const* ArtisanalProducer::pick_production_type(
346355
Pop& pop,
347-
PopValuesFromProvince const& values_from_province
356+
PopValuesFromProvince const& values_from_province,
357+
RandomU32& random_number_generator
348358
) const {
349359
bool should_pick_new_production_type;
350360
const auto ranked_artisanal_production_types = values_from_province.get_ranked_artisanal_production_types();
@@ -405,6 +415,12 @@ ProductionType const* ArtisanalProducer::pick_production_type(
405415
weights_sum += weight;
406416
}
407417

408-
//TODO randomly sample using weights
409-
return ranked_artisanal_production_types[0].first;
418+
const size_t sample_index = sample_weighted_index(
419+
random_number_generator(),
420+
weights,
421+
weights_sum
422+
);
423+
424+
assert(sample_index >= 0 && sample_index < ranked_artisanal_production_types.size());
425+
return ranked_artisanal_production_types[sample_index].first;
410426
}

src/openvic-simulation/economy/production/ArtisanalProducer.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace OpenVic {
1616
struct PopValuesFromProvince;
1717
struct ProductionType;
1818
struct ProvinceInstance;
19+
struct RandomU32;
1920

2021
struct ArtisanalProducer {
2122
private:
@@ -32,7 +33,8 @@ namespace OpenVic {
3233
void set_production_type(ProductionType const* const new_production_type);
3334
ProductionType const* pick_production_type(
3435
Pop& pop,
35-
PopValuesFromProvince const& values_from_province
36+
PopValuesFromProvince const& values_from_province,
37+
RandomU32& random_number_generator
3638
) const;
3739

3840
static fixed_point_t calculate_production_type_score(
@@ -58,6 +60,7 @@ namespace OpenVic {
5860
void artisan_tick(
5961
Pop& pop,
6062
PopValuesFromProvince const& values_from_province,
63+
RandomU32& random_number_generator,
6164
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
6265
memory::vector<fixed_point_t>& pop_max_quantity_to_buy_per_good,
6366
memory::vector<fixed_point_t>& pop_money_to_spend_per_good,

src/openvic-simulation/map/ProvinceInstance.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ void ProvinceInstance::update_gamestate(InstanceManager const& instance_manager)
389389
void ProvinceInstance::province_tick(
390390
const Date today,
391391
PopValuesFromProvince& reusable_pop_values,
392+
RandomU32& random_number_generator,
392393
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
393394
utility::forwardable_span<
394395
memory::vector<fixed_point_t>,
@@ -402,7 +403,12 @@ void ProvinceInstance::province_tick(
402403
if (!pops.empty()) {
403404
reusable_pop_values.update_pop_values_from_province(*this);
404405
for (Pop& pop : pops) {
405-
pop.pop_tick(reusable_pop_values, reusable_goods_mask, reusable_vectors);
406+
pop.pop_tick(
407+
reusable_pop_values,
408+
random_number_generator,
409+
reusable_goods_mask,
410+
reusable_vectors
411+
);
406412
}
407413
}
408414

@@ -513,14 +519,21 @@ bool ProvinceInstance::apply_history_to_province(ProvinceHistoryEntry const& ent
513519
void ProvinceInstance::initialise_for_new_game(
514520
const Date today,
515521
PopValuesFromProvince& reusable_pop_values,
522+
RandomU32& random_number_generator,
516523
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
517524
utility::forwardable_span<
518525
memory::vector<fixed_point_t>,
519526
VECTORS_FOR_PROVINCE_TICK
520527
> reusable_vectors
521528
) {
522529
initialise_rgo();
523-
province_tick(today, reusable_pop_values, reusable_goods_mask, reusable_vectors);
530+
province_tick(
531+
today,
532+
reusable_pop_values,
533+
random_number_generator,
534+
reusable_goods_mask,
535+
reusable_vectors
536+
);
524537
}
525538

526539
void ProvinceInstance::initialise_rgo() {

src/openvic-simulation/map/ProvinceInstance.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ namespace OpenVic {
194194
void province_tick(
195195
const Date today,
196196
PopValuesFromProvince& reusable_pop_values,
197+
RandomU32& random_number_generator,
197198
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
198199
utility::forwardable_span<
199200
memory::vector<fixed_point_t>,
@@ -203,6 +204,7 @@ namespace OpenVic {
203204
void initialise_for_new_game(
204205
const Date today,
205206
PopValuesFromProvince& reusable_pop_values,
207+
RandomU32& random_number_generator,
206208
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
207209
utility::forwardable_span<
208210
memory::vector<fixed_point_t>,

src/openvic-simulation/pop/Pop.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ void Pop::allocate_for_needs(
452452
}
453453

454454
void Pop::pop_tick(
455-
PopValuesFromProvince& shared_values,
455+
PopValuesFromProvince const& shared_values,
456+
RandomU32& random_number_generator,
456457
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
457458
utility::forwardable_span<
458459
memory::vector<fixed_point_t>,
@@ -461,6 +462,7 @@ void Pop::pop_tick(
461462
) {
462463
pop_tick_without_cleanup(
463464
shared_values,
465+
random_number_generator,
464466
reusable_goods_mask,
465467
reusable_vectors
466468
);
@@ -470,7 +472,8 @@ void Pop::pop_tick(
470472
}
471473

472474
void Pop::pop_tick_without_cleanup(
473-
PopValuesFromProvince& shared_values,
475+
PopValuesFromProvince const& shared_values,
476+
RandomU32& random_number_generator,
474477
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
475478
utility::forwardable_span<
476479
memory::vector<fixed_point_t>,
@@ -494,6 +497,7 @@ void Pop::pop_tick_without_cleanup(
494497
artisanal_producer.artisan_tick(
495498
*this,
496499
shared_values,
500+
random_number_generator,
497501
reusable_goods_mask,
498502
max_quantity_to_buy_per_good,
499503
money_to_spend_per_good,

src/openvic-simulation/pop/Pop.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ namespace OpenVic {
172172
fixed_point_t& cash_left_to_spend
173173
);
174174
void pop_tick_without_cleanup(
175-
PopValuesFromProvince& shared_values,
175+
PopValuesFromProvince const& shared_values,
176+
RandomU32& random_number_generator,
176177
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
177178
utility::forwardable_span<
178179
memory::vector<fixed_point_t>,
@@ -211,7 +212,8 @@ namespace OpenVic {
211212
#undef DECLARE_POP_MONEY_STORE_FUNCTIONS
212213

213214
void pop_tick(
214-
PopValuesFromProvince& shared_values,
215+
PopValuesFromProvince const& shared_values,
216+
RandomU32& random_number_generator,
215217
IndexedFlatMap<GoodDefinition, char>& reusable_goods_mask,
216218
utility::forwardable_span<
217219
memory::vector<fixed_point_t>,

src/openvic-simulation/utility/ThreadPool.cpp

Lines changed: 81 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ void ThreadPool::loop_until_cancelled(
1919
utility::forwardable_span<const CountryInstance> country_keys,
2020
utility::forwardable_span<const GoodDefinition> good_keys,
2121
utility::forwardable_span<const Strata> strata_keys,
22-
utility::forwardable_span<GoodInstance> goods_chunk,
23-
utility::forwardable_span<CountryInstance> countries_chunk,
24-
utility::forwardable_span<ProvinceInstance> provinces_chunk
22+
utility::forwardable_span<WorkBundle> work_bundles
2523
) {
2624
IndexedFlatMap<GoodDefinition, char> reusable_goods_mask { good_keys };
2725
IndexedFlatMap<CountryInstance, fixed_point_t> reusable_country_map_0 { country_keys },
@@ -67,46 +65,58 @@ void ThreadPool::loop_until_cancelled(
6765
case work_t::NONE:
6866
break;
6967
case work_t::GOOD_EXECUTE_ORDERS:
70-
for (GoodMarket& good : goods_chunk) {
71-
good.execute_orders(
72-
reusable_country_map_0,
73-
reusable_country_map_1,
74-
reusable_vectors_span.first<GoodMarket::VECTORS_FOR_EXECUTE_ORDERS>()
75-
);
68+
for (WorkBundle& work_bundle : work_bundles) {
69+
for (GoodMarket& good : work_bundle.goods_chunk) {
70+
good.execute_orders(
71+
reusable_country_map_0,
72+
reusable_country_map_1,
73+
reusable_vectors_span.first<GoodMarket::VECTORS_FOR_EXECUTE_ORDERS>()
74+
);
75+
}
7676
}
7777
break;
7878
case work_t::PROVINCE_TICK:
79-
for (ProvinceInstance& province : provinces_chunk) {
80-
province.province_tick(
81-
current_date,
82-
reusable_pop_values,
83-
reusable_goods_mask,
84-
reusable_vectors_span.first<ProvinceInstance::VECTORS_FOR_PROVINCE_TICK>()
85-
);
79+
for (WorkBundle& work_bundle : work_bundles) {
80+
for (ProvinceInstance& province : work_bundle.provinces_chunk) {
81+
province.province_tick(
82+
current_date,
83+
reusable_pop_values,
84+
work_bundle.random_number_generator,
85+
reusable_goods_mask,
86+
reusable_vectors_span.first<ProvinceInstance::VECTORS_FOR_PROVINCE_TICK>()
87+
);
88+
}
8689
}
8790
break;
8891
case work_t::PROVINCE_INITIALISE_FOR_NEW_GAME:
89-
for (ProvinceInstance& province : provinces_chunk) {
90-
province.initialise_for_new_game(
91-
current_date,
92-
reusable_pop_values,
93-
reusable_goods_mask,
94-
reusable_vectors_span.first<ProvinceInstance::VECTORS_FOR_PROVINCE_TICK>()
95-
);
92+
for (WorkBundle& work_bundle : work_bundles) {
93+
for (ProvinceInstance& province : work_bundle.provinces_chunk) {
94+
province.initialise_for_new_game(
95+
current_date,
96+
reusable_pop_values,
97+
work_bundle.random_number_generator,
98+
reusable_goods_mask,
99+
reusable_vectors_span.first<ProvinceInstance::VECTORS_FOR_PROVINCE_TICK>()
100+
);
101+
}
96102
}
97103
break;
98104
case work_t::COUNTRY_TICK_BEFORE_MAP:
99-
for (CountryInstance& country : countries_chunk) {
100-
country.country_tick_before_map(
101-
reusable_goods_mask,
102-
reusable_vectors_span.first<CountryInstance::VECTORS_FOR_COUNTRY_TICK>(),
103-
reusable_index_vector
104-
);
105+
for (WorkBundle& work_bundle : work_bundles) {
106+
for (CountryInstance& country : work_bundle.countries_chunk) {
107+
country.country_tick_before_map(
108+
reusable_goods_mask,
109+
reusable_vectors_span.first<CountryInstance::VECTORS_FOR_COUNTRY_TICK>(),
110+
reusable_index_vector
111+
);
112+
}
105113
}
106114
break;
107115
case work_t::COUNTRY_TICK_AFTER_MAP:
108-
for (CountryInstance& country : countries_chunk) {
109-
country.country_tick_after_map(current_date);
116+
for (WorkBundle& work_bundle : work_bundles) {
117+
for (CountryInstance& country : work_bundle.countries_chunk) {
118+
country.country_tick_after_map(current_date);
119+
}
110120
}
111121
break;
112122
}
@@ -181,18 +191,17 @@ void ThreadPool::initialise_threadpool(
181191
return;
182192
}
183193

184-
const size_t max_worker_threads = std::max<size_t>(std::thread::hardware_concurrency(), 1);
185-
threads.reserve(max_worker_threads);
186-
work_per_thread.resize(max_worker_threads, work_t::NONE);
194+
RandomU32 master_rng { }; //TODO seed?
187195

188-
const auto [goods_quotient, goods_remainder] = std::ldiv(goods.size(), max_worker_threads);
189-
const auto [countries_quotient, countries_remainder] = std::ldiv(countries.size(), max_worker_threads);
190-
const auto [provinces_quotient, provinces_remainder] = std::ldiv(provinces.size(), max_worker_threads);
196+
197+
const auto [goods_quotient, goods_remainder] = std::ldiv(goods.size(), WORK_BUNDLE_COUNT);
198+
const auto [countries_quotient, countries_remainder] = std::ldiv(countries.size(), WORK_BUNDLE_COUNT);
199+
const auto [provinces_quotient, provinces_remainder] = std::ldiv(provinces.size(), WORK_BUNDLE_COUNT);
191200
auto goods_begin = goods.begin();
192201
auto countries_begin = countries.begin();
193202
auto provinces_begin = provinces.begin();
194203

195-
for (size_t i = 0; i < max_worker_threads; i++) {
204+
for (size_t i = 0; i < WORK_BUNDLE_COUNT; i++) {
196205
const size_t goods_chunk_size = i < goods_remainder
197206
? goods_quotient + 1
198207
: goods_quotient;
@@ -207,6 +216,36 @@ void ThreadPool::initialise_threadpool(
207216
auto countries_end = countries_begin + countries_chunk_size;
208217
auto provinces_end = provinces_begin + provinces_chunk_size;
209218

219+
all_work_bundles[i] = WorkBundle {
220+
master_rng.generator().serialize(),
221+
std::span<CountryInstance>{ countries_begin, countries_end },
222+
std::span<GoodInstance>{ goods_begin, goods_end },
223+
std::span<ProvinceInstance>{ provinces_begin, provinces_end }
224+
};
225+
226+
//ensure different state for next WorkBundle
227+
master_rng.generator().jump();
228+
229+
goods_begin = goods_end;
230+
countries_begin = countries_end;
231+
provinces_begin = provinces_end;
232+
}
233+
234+
const size_t max_worker_threads = std::max<size_t>(std::thread::hardware_concurrency(), 1);
235+
threads.reserve(max_worker_threads);
236+
work_per_thread.resize(max_worker_threads, work_t::NONE);
237+
238+
239+
const auto [work_bundles_quotient, work_bundles_remainder] = std::ldiv(WORK_BUNDLE_COUNT, max_worker_threads);
240+
auto work_bundles_begin = all_work_bundles.begin();
241+
242+
for (size_t i = 0; i < max_worker_threads; ++i) {
243+
const size_t work_bundles_chunk_size = i < work_bundles_remainder
244+
? work_bundles_quotient + 1
245+
: work_bundles_quotient;
246+
247+
auto work_bundles_end = work_bundles_begin + work_bundles_chunk_size;
248+
210249
threads.emplace_back(
211250
[
212251
this,
@@ -219,9 +258,8 @@ void ThreadPool::initialise_threadpool(
219258
countries,
220259
good_keys,
221260
strata_keys,
222-
goods_begin, goods_end,
223-
countries_begin, countries_end,
224-
provinces_begin, provinces_end
261+
work_bundles_begin,
262+
work_bundles_end
225263
]() -> void {
226264
loop_until_cancelled(
227265
work_for_thread,
@@ -233,16 +271,12 @@ void ThreadPool::initialise_threadpool(
233271
countries,
234272
good_keys,
235273
strata_keys,
236-
std::span<GoodInstance>{ goods_begin, goods_end },
237-
std::span<CountryInstance>{ countries_begin, countries_end },
238-
std::span<ProvinceInstance>{ provinces_begin, provinces_end }
274+
std::span<WorkBundle>{ work_bundles_begin, work_bundles_end }
239275
);
240276
}
241277
);
242278

243-
goods_begin = goods_end;
244-
countries_begin = countries_end;
245-
provinces_begin = provinces_end;
279+
work_bundles_begin = work_bundles_end;
246280
}
247281
}
248282

0 commit comments

Comments
 (0)