summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bench/bench_window.cpp18
-rw-r--r--include/lib94/lib94.hpp19
-rw-r--r--lib94/core.cpp43
-rw-r--r--tabulator-mpi/main.cpp9
-rw-r--r--tabulator-mpi/worker.cpp3
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>();