diff options
-rw-r--r-- | bench/bench_window.cpp | 18 | ||||
-rw-r--r-- | include/lib94/lib94.hpp | 19 | ||||
-rw-r--r-- | lib94/core.cpp | 43 | ||||
-rw-r--r-- | tabulator-mpi/main.cpp | 9 | ||||
-rw-r--r-- | tabulator-mpi/worker.cpp | 3 |
5 files changed, 64 insertions, 28 deletions
diff --git a/bench/bench_window.cpp b/bench/bench_window.cpp index 70cbbbf..99d7926 100644 --- a/bench/bench_window.cpp +++ b/bench/bench_window.cpp @@ -1,3 +1,4 @@ +#include <cassert> #include <fstream> #include "bench_window.hpp" @@ -193,7 +194,22 @@ void bench_window::on_click_new_round() { .bnumber = 0 }); - lib94::init_round(warriors.data(), warriors.size()); + if (!lib94::init_round(warriors.data(), warriors.size())) { + Gtk::MessageDialog *md = new Gtk::MessageDialog("warriors do not fit in core; removing last warrior"); + md->set_transient_for(*this); + md->set_modal(); + md->signal_response().connect([md](int) {delete md;}); + md->show(); + + //is this safe? + delete warriors.back(); + warriors.pop_back(); + if (warriors.size() == 0) { + update_ui(); + return; + } + assert(lib94::init_round(warriors.data(), warriors.size())); + } core.mut.lock(); core.age_scale = std::pow(2.0 / 3.0, 1.0 / (float)warriors.size()); diff --git a/include/lib94/lib94.hpp b/include/lib94/lib94.hpp index c91c24b..4924732 100644 --- a/include/lib94/lib94.hpp +++ b/include/lib94/lib94.hpp @@ -91,16 +91,15 @@ namespace lib94 { //does not effect the address sets. void clear_core_random(); - //clears the address sets, places the supplied warriors into the core, and starts one - //process for each supplied warrior at its org. the count parameter specifies the - //number of warriors in the array. note that, if the supplied warriors cannot all be - //fit into the core, this will never return. the each of the warriors in the array - //must not be deleted for the duration of the round, but the array itself may be - //deleted after this function returns. note that this function does not clear the core - //before placing the warriors, so you may want to call clear_core or clear_core_random - //before calling this. note also that you probably want to call seed_prng, for example - //with the current time, before the first time you call this. - void init_round(const warrior *const *warriors, size_t count); + //clears the address sets, places the supplied warriors into the core, and starts one process for + //each supplied warrior at its org. the count parameter specifies the number of warriors in the + //array. each of the warriors in the array must not be deleted for the duration of the round, but + //the array itself may be deleted after this function returns. on success, this function returns + //true. on failure (i.e. when the warriors do not all fit into the core), this function returns + //false. note that this function does not clear the core before placing the warriors, so you may + //want to call clear_core or clear_core_random before calling this. note also that you probably + //want to call seed_prng, for example with the current time, before the first time you call this. + bool init_round(const warrior *const *warriors, size_t count); //returns the number of warriors who have at least one process size_t alive_warrior_count(); diff --git a/lib94/core.cpp b/lib94/core.cpp index 1693c39..5a2654d 100644 --- a/lib94/core.cpp +++ b/lib94/core.cpp @@ -55,44 +55,55 @@ namespace lib94 { static std::vector<warrior_info> warrior_infos; std::deque<warrior_info *> alive_warriors; - void init_round(const warrior *const *warriors, size_t count) { + bool init_round(const warrior *const *warriors, size_t count) { clear_address_sets(); warrior_infos.clear(); alive_warriors = std::deque<warrior_info *>(); - std::uniform_int_distribution<number_t> number(0, LIB94_CORE_SIZE - 1); - std::vector<std::pair<number_t, number_t>> placements; + std::vector<number_t> gap_sizes; + gap_sizes.resize(count); + + std::uniform_real_distribution phi_dist(0.0, 1.0); + number_t gap_remaining = LIB94_CORE_SIZE; for (size_t i = 0; i < count; ++i) { - const warrior *w = warriors[i]; + number_t wlength = warriors[i]->instructions.size(); + if (wlength > gap_remaining) + return false; + gap_remaining -= wlength; + } - new_place_at: - number_t place_at = i == 0 ? 0 : number(prng); + for (size_t i = 0; i < count; ++i) { + number_t gap_size = std::floor(gap_remaining * (1.0 - std::pow(phi_dist(prng), 1.0 / (count - i)))); + gap_sizes[i] = gap_size; + gap_remaining -= gap_size; + } - for (const std::pair<number_t, number_t> &other : placements) - //there has to be a better way - for (number_t i = 0; i < (number_t)w->instructions.size(); ++i) - if (((place_at + i) % LIB94_CORE_SIZE >= other.first && (place_at + i) % LIB94_CORE_SIZE < other.first + other.second) || - ((place_at + i) % LIB94_CORE_SIZE + LIB94_CORE_SIZE >= other.first && (place_at + i) % LIB94_CORE_SIZE + LIB94_CORE_SIZE < other.first + other.second)) - goto new_place_at; + size_t place_at = 0; - placements.push_back(std::make_pair<>(place_at, w->instructions.size())); + for (size_t i = 0; i < count; ++i) { + const warrior *w = warriors[i]; for (number_t i = 0; i < (number_t)w->instructions.size(); ++i) { - core[(place_at + i) % LIB94_CORE_SIZE] = w->instructions[i]; - add_written_instruction(core + (place_at + i) % LIB94_CORE_SIZE); + assert(place_at + i < LIB94_CORE_SIZE); + core[place_at + i] = w->instructions[i]; + add_written_instruction(core + place_at + i); } warrior_infos.push_back({}); warrior_info *wi = &warrior_infos.back(); wi->the_warrior = w; - wi->processes.push_back((place_at + w->org) % LIB94_CORE_SIZE); + assert(place_at + w->org < LIB94_CORE_SIZE); + wi->processes.push_back(place_at + w->org); + + place_at += w->instructions.size() + gap_sizes[i]; } std::shuffle(warrior_infos.begin(), warrior_infos.end(), prng); for (warrior_info &wi : warrior_infos) alive_warriors.push_back(&wi); + return true; } size_t alive_warrior_count() { diff --git a/tabulator-mpi/main.cpp b/tabulator-mpi/main.cpp index e6e1a27..cd17044 100644 --- a/tabulator-mpi/main.cpp +++ b/tabulator-mpi/main.cpp @@ -42,6 +42,15 @@ int main(int argc, char **argv) { for (int i = 0; i < argc - 1; ++i) warriors[i] = load_warrior(argv[i + 1]); + for (int i = 0; i < argc - 1; ++i) + for (int j = i + 1; j < argc - 1; ++j) { + const lib94::warrior *wbuf[2] = {warriors[i], warriors[j]}; + if (!lib94::init_round(wbuf, 2)) { + fprintf(stderr, "warriors do not fit in core\n"); + return 1; + } + } + if (comm_rank == 0) head_main(comm_size, argc - 1, warriors); else diff --git a/tabulator-mpi/worker.cpp b/tabulator-mpi/worker.cpp index 511a27a..486d107 100644 --- a/tabulator-mpi/worker.cpp +++ b/tabulator-mpi/worker.cpp @@ -1,4 +1,5 @@ #include <lib94/lib94.hpp> +#include <cassert> #include <ctime> #include <mpi.h> @@ -15,7 +16,7 @@ static void do_round(const lib94::warrior *w1, const lib94::warrior *w2, int &w1 lib94::clear_core(background); - lib94::init_round(ws, 2); + assert(lib94::init_round(ws, 2)); for (int i = 0; i < STEPS_TO_TIE; ++i) { const lib94::warrior *result = lib94::single_step<false>(); |