The CLion linter is a beast

This commit is contained in:
James P. Howard, II
2021-09-25 12:15:36 -04:00
parent b02efaae07
commit 584c2b94d8
32 changed files with 1294 additions and 1449 deletions

View File

@@ -1,6 +1,7 @@
Changelog Changelog
========= =========
- :bug:`0` Cleaned up numerous issues found by CLion's linter
- :feature:`0` Added a new overview to the documents - :feature:`0` Added a new overview to the documents
- :feature:`0` Added basic installation instructions - :feature:`0` Added basic installation instructions
- :bug:`0` Retagged previous versions using pure Semantic Versioning - :bug:`0` Retagged previous versions using pure Semantic Versioning

View File

@@ -23,25 +23,23 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include "boltzmann1d.h" #include <map>
#include <memory>
#include <random>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/grid1d.h>
#include <kami/kami.h> #include <kami/kami.h>
#include <kami/multigrid1d.h> #include <kami/multigrid1d.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/stopwatch.h> #include <spdlog/stopwatch.h>
#include <stdlib.h>
#include <CLI/App.hpp> #include <CLI/App.hpp>
#include <CLI/Config.hpp> #include <CLI/Config.hpp>
#include <CLI/Formatter.hpp> #include <CLI/Formatter.hpp>
#include <iostream>
#include <map> #include "boltzmann1d.h"
#include <memory>
#include <random>
#include <string>
using namespace kami; using namespace kami;
using namespace std; using namespace std;
@@ -53,14 +51,14 @@ shared_ptr<mt19937> rng = nullptr;
template <> template <>
struct fmt::formatter<AgentID> : fmt::formatter<string> { struct fmt::formatter<AgentID> : fmt::formatter<string> {
auto format(AgentID agent_id, format_context &ctx) { [[maybe_unused]] static auto format(AgentID agent_id, format_context &ctx) {
return format_to(ctx.out(), "{}", agent_id.to_string()); return format_to(ctx.out(), "{}", agent_id.to_string());
} }
}; };
template <> template <>
struct fmt::formatter<GridCoord1D> : fmt::formatter<string> { struct fmt::formatter<GridCoord1D> : fmt::formatter<string> {
auto format(GridCoord1D coord, format_context &ctx) { [[maybe_unused]] static auto format(const GridCoord1D& coord, format_context &ctx) {
return format_to(ctx.out(), "{}", coord.to_string()); return format_to(ctx.out(), "{}", coord.to_string());
} }
}; };
@@ -82,7 +80,7 @@ void MoneyAgent1D::move_agent() {
console->trace("Entering move_agent"); console->trace("Entering move_agent");
auto agent_id = get_agent_id(); auto agent_id = get_agent_id();
auto move_list = _world->get_neighborhood(agent_id, false); auto move_list = _world->get_neighborhood(agent_id, false);
std::uniform_int_distribution<int> dist(0, move_list.size() - 1); std::uniform_int_distribution<int> dist(0, (int)move_list.size() - 1);
auto new_location = move_list[dist(*rng)]; auto new_location = move_list[dist(*rng)];
console->trace("Moving Agent {} to location {}", agent_id, new_location); console->trace("Moving Agent {} to location {}", agent_id, new_location);
@@ -90,29 +88,23 @@ void MoneyAgent1D::move_agent() {
console->trace("Exiting move_agent"); console->trace("Exiting move_agent");
} }
int MoneyAgent1D::get_wealth() { return _agent_wealth; }
void MoneyAgent1D::set_wealth(int wealth) { _agent_wealth = wealth; }
void MoneyAgent1D::give_money() { void MoneyAgent1D::give_money() {
AgentID agent_id = get_agent_id(); AgentID agent_id = get_agent_id();
GridCoord1D location = _world->get_location_by_agent(agent_id); GridCoord1D location = _world->get_location_by_agent(agent_id);
vector<AgentID> *cell_mates = _world->get_location_contents(location); vector<AgentID> *cell_mates = _world->get_location_contents(location);
if (cell_mates->size() > 1) { if (cell_mates->size() > 1) {
std::uniform_int_distribution<int> dist(0, cell_mates->size() - 1); std::uniform_int_distribution<int> dist(0, (int)cell_mates->size() - 1);
AgentID other_agent_id = cell_mates->at(dist(*rng)); AgentID other_agent_id = cell_mates->at(dist(*rng));
auto other_agent = _model->get_agent_by_id(other_agent_id); auto other_agent = _model->get_agent_by_id(other_agent_id);
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
other_agent_id);
other_agent->_agent_wealth += 1; other_agent->_agent_wealth += 1;
_agent_wealth -= 1; _agent_wealth -= 1;
} }
} }
BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents, BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents, unsigned int length_x) {
unsigned int length_x) {
_world = new MultiGrid1D(length_x, true); _world = new MultiGrid1D(length_x, true);
_sched = new RandomScheduler(this, rng); _sched = new RandomScheduler(this, rng);
@@ -120,23 +112,20 @@ BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents,
MoneyAgent1D::set_world(_world); MoneyAgent1D::set_world(_world);
MoneyAgent1D::set_model(this); MoneyAgent1D::set_model(this);
std::uniform_int_distribution<int> dist(0, length_x - 1); std::uniform_int_distribution<int> dist(0, (int)length_x - 1);
for (unsigned int i = 0; i < number_agents; i++) { for (unsigned int i = 0; i < number_agents; i++) {
MoneyAgent1D *new_agent = new MoneyAgent1D(); auto *new_agent = new MoneyAgent1D();
_agent_list.insert(pair<AgentID, MoneyAgent1D *>( _agent_list.insert(pair<AgentID, MoneyAgent1D *>(new_agent->get_agent_id(), new_agent));
new_agent->get_agent_id(), new_agent));
_sched->add_agent(new_agent->get_agent_id()); _sched->add_agent(new_agent->get_agent_id());
_world->add_agent(new_agent->get_agent_id(), GridCoord1D(dist(*rng))); _world->add_agent(new_agent->get_agent_id(), GridCoord1D(dist(*rng)));
} }
} }
BoltzmannWealthModel1D::~BoltzmannWealthModel1D() { BoltzmannWealthModel1D::~BoltzmannWealthModel1D() {
for (auto agent_pair = _agent_list.begin(); agent_pair != _agent_list.end(); for (auto & agent_pair : _agent_list)
agent_pair++) { delete agent_pair.second;
delete agent_pair->second;
}
delete _sched; delete _sched;
delete _world; delete _world;
@@ -161,29 +150,19 @@ int main(int argc, char **argv) {
string ident = "boltzmann1d"; string ident = "boltzmann1d";
CLI::App app{ident}; CLI::App app{ident};
string log_level_option = "info"; string log_level_option = "info";
unsigned int x_size = 16, agent_count = x_size, max_steps = 100, unsigned int x_size = 16, agent_count = x_size, max_steps = 100, initial_seed = 42;
initial_seed = 42;
app.add_option("-c", agent_count, "Set the number of agents") app.add_option("-c", agent_count, "Set the number of agents")->check(CLI::PositiveNumber);
->check(CLI::PositiveNumber); app.add_option("-l", log_level_option, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
app.add_option("-l", log_level_option, "Set the logging level") app.add_option("-n", max_steps, "Set the number of steps to run the model")->check(CLI::PositiveNumber);
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES)); app.add_option("-s", initial_seed, "Set the initial seed")->check(CLI::Number);
app.add_option("-n", max_steps, "Set the number of steps to run the model") app.add_option("-x", x_size, "Set the number of columns")->check(CLI::PositiveNumber);
->check(CLI::PositiveNumber);
app.add_option("-s", initial_seed, "Set the initial seed")
->check(CLI::Number);
app.add_option("-x", x_size, "Set the number of colums")
->check(CLI::PositiveNumber);
CLI11_PARSE(app, argc, argv); CLI11_PARSE(app, argc, argv);
console = spdlog::stdout_color_st(ident); console = spdlog::stdout_color_st(ident);
console->set_level(spdlog::level::from_str(log_level_option)); console->set_level(spdlog::level::from_str(log_level_option));
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, log_level_option);
log_level_option); console->info("Starting Boltzmann Wealth Model with {} agents on a {}-unit grid for {} steps",agent_count, x_size, max_steps);
console->info(
"Starting Boltzmann Wealth Model with {} agents on a {}-unit grid for "
"{} steps",
agent_count, x_size, max_steps);
rng = make_shared<mt19937>(initial_seed); rng = make_shared<mt19937>(initial_seed);
BoltzmannWealthModel1D model(agent_count, x_size); BoltzmannWealthModel1D model(agent_count, x_size);
@@ -193,6 +172,5 @@ int main(int argc, char **argv) {
console->trace("Initiating model step {}", i); console->trace("Initiating model step {}", i);
model.step(); model.step();
} }
console->info( console->info("Boltzmann Wealth Model simulation complete, requiring {} seconds", sw);
"Boltzman Wealth Model simulation complete, requiring {} seconds", sw);
} }

View File

@@ -24,17 +24,16 @@
*/ */
#pragma once #pragma once
#ifndef BOLTZMAN1D_H #ifndef BOLTZMANN1D_H
#define BOLTZMAN1D_H #define BOLTZMANN1D_H
#include <iostream>
#include <map>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/kami.h> #include <kami/kami.h>
#include <kami/multigrid1d.h> #include <kami/multigrid1d.h>
#include <kami/random.h> #include <kami/random.h>
#include <spdlog/spdlog.h>
#include <iostream>
#include <map>
using namespace kami; using namespace kami;
using namespace std; using namespace std;
@@ -43,7 +42,7 @@ using namespace std;
* A sample agent for a one-dimensional Boltzmann wealth model * A sample agent for a one-dimensional Boltzmann wealth model
*/ */
class MoneyAgent1D : public Agent { class MoneyAgent1D : public Agent {
public: public:
/** /**
* Create the agent * Create the agent
*/ */
@@ -52,7 +51,7 @@ class MoneyAgent1D : public Agent {
/** /**
* Execute a single time-step for the agent * Execute a single time-step for the agent
*/ */
void step(); void step() override;
/** /**
* Give the agent a reference copy of the domain it is expected to work in * Give the agent a reference copy of the domain it is expected to work in
@@ -69,22 +68,12 @@ class MoneyAgent1D : public Agent {
*/ */
void move_agent(); void move_agent();
/**
* Return the wealth of the agent
*/
int get_wealth();
/**
* Set the wealth of the agent
*/
void set_wealth(int wealth);
/** /**
* Give money to a random agent * Give money to a random agent
*/ */
void give_money(); void give_money();
private: private:
static MultiGrid1D *_world; static MultiGrid1D *_world;
static BoltzmannWealthModel1D *_model; static BoltzmannWealthModel1D *_model;
int _step_counter; int _step_counter;
@@ -95,16 +84,15 @@ class MoneyAgent1D : public Agent {
* The one-dimensional Boltzmann wealth model * The one-dimensional Boltzmann wealth model
*/ */
class BoltzmannWealthModel1D : public Model { class BoltzmannWealthModel1D : public Model {
public: public:
/** /**
* Create an instance of the one-dimensional Boltzman wealth model. * Create an instance of the one-dimensional Boltzmann wealth model.
* *
* @param[in] number_agents the number of agents to assign to the model. * @param[in] number_agents the number of agents to assign to the model.
* @param[in] length_x the length of the one-dimensional world the agents * @param[in] length_x the length of the one-dimensional world the agents
* occupy. * occupy.
*/ */
BoltzmannWealthModel1D(unsigned int number_agents = 10, explicit BoltzmannWealthModel1D(unsigned int number_agents = 10, unsigned int length_x = 10);
unsigned int length_x = 10);
/** /**
* Destroy the instance * Destroy the instance
@@ -114,27 +102,27 @@ class BoltzmannWealthModel1D : public Model {
/** /**
* Execute a single time-step for the model. * Execute a single time-step for the model.
*/ */
void step(); void step() override;
/** /**
* Execute a number of time-steps for the model. * Execute a number of time-steps for the model.
* *
* @param[in] n the number of steps to execute. * @param[in] n the number of steps to execute.
*/ */
void run(unsigned int n); void run(unsigned int n) override;
/** /**
* Get the MoneyAgent instance associated with the given `AgentID` * Get the MoneyAgent instance associated with the given `AgentID`
* *
* @returns an pointer to the `MoneyAgent` that was requested. * @returns an pointer to the `MoneyAgent` that was requested.
*/ */
MoneyAgent1D *get_agent_by_id(AgentID agent_id) const; [[nodiscard]] MoneyAgent1D *get_agent_by_id(AgentID agent_id) const override;
private: private:
map<AgentID, MoneyAgent1D *> _agent_list; map<AgentID, MoneyAgent1D *> _agent_list;
RandomScheduler *_sched; RandomScheduler *_sched;
MultiGrid1D *_world; MultiGrid1D *_world;
unsigned int _step_count; unsigned int _step_count;
}; };
#endif // BOLTZMAN1D_H #endif // BOLTZMANN1D_H

View File

@@ -23,23 +23,21 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <map>
#include <memory>
#include <random>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/grid2d.h>
#include <kami/kami.h> #include <kami/kami.h>
#include <kami/multigrid1d.h> #include <kami/multigrid2d.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/stopwatch.h> #include <spdlog/stopwatch.h>
#include <stdlib.h>
#include <CLI/App.hpp> #include <CLI/App.hpp>
#include <CLI/Config.hpp> #include <CLI/Config.hpp>
#include <CLI/Formatter.hpp> #include <CLI/Formatter.hpp>
#include <iostream>
#include <map>
#include <memory>
#include <random>
#include <string>
#include "boltzmann2d.h" #include "boltzmann2d.h"
@@ -53,14 +51,14 @@ shared_ptr<mt19937> rng = nullptr;
template <> template <>
struct fmt::formatter<AgentID> : fmt::formatter<string> { struct fmt::formatter<AgentID> : fmt::formatter<string> {
auto format(AgentID agent_id, format_context &ctx) { [[maybe_unused]] static auto format(AgentID agent_id, format_context &ctx) {
return format_to(ctx.out(), "{}", agent_id.to_string()); return format_to(ctx.out(), "{}", agent_id.to_string());
} }
}; };
template <> template <>
struct fmt::formatter<GridCoord2D> : fmt::formatter<string> { struct fmt::formatter<GridCoord2D> : fmt::formatter<string> {
auto format(GridCoord2D coord, format_context &ctx) { [[maybe_unused]] static auto format(const GridCoord2D& coord, format_context &ctx) {
return format_to(ctx.out(), "{}", coord.to_string()); return format_to(ctx.out(), "{}", coord.to_string());
} }
}; };
@@ -82,7 +80,7 @@ void MoneyAgent2D::move_agent() {
console->trace("Entering move_agent"); console->trace("Entering move_agent");
auto agent_id = get_agent_id(); auto agent_id = get_agent_id();
auto move_list = _world->get_neighborhood(agent_id, GridNeighborhoodType::Moore, false); auto move_list = _world->get_neighborhood(agent_id, GridNeighborhoodType::Moore, false);
std::uniform_int_distribution<int> dist(0, move_list.size() - 1); std::uniform_int_distribution<int> dist(0, (int) move_list.size() - 1);
auto new_location = move_list[dist(*rng)]; auto new_location = move_list[dist(*rng)];
console->trace("Moving Agent {} to location {}", agent_id, new_location); console->trace("Moving Agent {} to location {}", agent_id, new_location);
@@ -90,31 +88,23 @@ void MoneyAgent2D::move_agent() {
console->trace("Exiting move_agent"); console->trace("Exiting move_agent");
} }
int MoneyAgent2D::get_wealth() { return _agent_wealth; }
void MoneyAgent2D::set_wealth(int newWealth) { _agent_wealth = newWealth; }
void MoneyAgent2D::give_money() { void MoneyAgent2D::give_money() {
AgentID agent_id = get_agent_id(); AgentID agent_id = get_agent_id();
GridCoord2D location = _world->get_location_by_agent(agent_id); GridCoord2D location = _world->get_location_by_agent(agent_id);
vector<AgentID> *cell_mates = _world->get_location_contents(location); vector<AgentID> *cell_mates = _world->get_location_contents(location);
if (cell_mates->size() > 1) { if (cell_mates->size() > 1) {
std::uniform_int_distribution<int> dist(0, cell_mates->size() - 1); std::uniform_int_distribution<int> dist(0, (int)cell_mates->size() - 1);
AgentID other_agent_id = cell_mates->at(dist(*rng)); AgentID other_agent_id = cell_mates->at(dist(*rng));
auto other_agent = _model->get_agent_by_id(other_agent_id); auto other_agent = _model->get_agent_by_id(other_agent_id);
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
other_agent_id);
other_agent->_agent_wealth += 1; other_agent->_agent_wealth += 1;
_agent_wealth -= 1; _agent_wealth -= 1;
} }
} }
BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents, BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents, unsigned int length_x, unsigned int length_y, unsigned int new_seed) {
unsigned int length_x,
unsigned int length_y,
unsigned int new_seed) {
rng = make_shared<mt19937>(); rng = make_shared<mt19937>();
rng->seed(new_seed); rng->seed(new_seed);
@@ -127,25 +117,21 @@ BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents,
MoneyAgent2D::set_world(_world); MoneyAgent2D::set_world(_world);
MoneyAgent2D::set_model(this); MoneyAgent2D::set_model(this);
std::uniform_int_distribution<int> dist_x(0, length_x - 1); std::uniform_int_distribution<int> dist_x(0, (int)length_x - 1);
std::uniform_int_distribution<int> dist_y(0, length_y - 1); std::uniform_int_distribution<int> dist_y(0, (int)length_y - 1);
for (unsigned int i = 0; i < number_agents; i++) { for (unsigned int i = 0; i < number_agents; i++) {
MoneyAgent2D *new_agent = new MoneyAgent2D(); auto *new_agent = new MoneyAgent2D();
_agent_list.insert(pair<AgentID, MoneyAgent2D *>( _agent_list.insert(pair<AgentID, MoneyAgent2D *>(new_agent->get_agent_id(), new_agent));
new_agent->get_agent_id(), new_agent));
_sched->add_agent(new_agent->get_agent_id()); _sched->add_agent(new_agent->get_agent_id());
_world->add_agent(new_agent->get_agent_id(), _world->add_agent(new_agent->get_agent_id(), GridCoord2D(dist_x(*rng), dist_x(*rng)));
GridCoord2D(dist_x(*rng), dist_x(*rng)));
} }
} }
BoltzmannWealthModel2D::~BoltzmannWealthModel2D() { BoltzmannWealthModel2D::~BoltzmannWealthModel2D() {
for (auto agent_pair = _agent_list.begin(); agent_pair != _agent_list.end(); for (auto & agent_pair : _agent_list)
agent_pair++) { delete agent_pair.second;
delete agent_pair->second;
}
delete _sched; delete _sched;
delete _world; delete _world;
@@ -169,31 +155,20 @@ int main(int argc, char **argv) {
std::string ident = "boltzmann2d"; std::string ident = "boltzmann2d";
CLI::App app{ident}; CLI::App app{ident};
string log_level_option = "info"; string log_level_option = "info";
unsigned int x_size = 16, y_size = 16, agent_count = x_size * y_size, unsigned int x_size = 16, y_size = 16, agent_count = x_size * y_size, max_steps = 100, initial_seed = 42;
max_steps = 100, initial_seed = 42;
app.add_option("-c", agent_count, "Set the number of agents") app.add_option("-c", agent_count, "Set the number of agents")->check(CLI::PositiveNumber);
->check(CLI::PositiveNumber); app.add_option("-l", log_level_option, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
app.add_option("-l", log_level_option, "Set the logging level") app.add_option("-n", max_steps, "Set the number of steps to run the model")->check(CLI::PositiveNumber);
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES)); app.add_option("-s", initial_seed, "Set the initial seed")->check(CLI::Number);
app.add_option("-n", max_steps, "Set the number of steps to run the model") app.add_option("-x", x_size, "Set the number of columns")->check(CLI::PositiveNumber);
->check(CLI::PositiveNumber); app.add_option("-y", y_size, "Set the number of rows")->check(CLI::PositiveNumber);
app.add_option("-s", initial_seed, "Set the initial seed")
->check(CLI::Number);
app.add_option("-x", x_size, "Set the number of colums")
->check(CLI::PositiveNumber);
app.add_option("-y", y_size, "Set the number of rows")
->check(CLI::PositiveNumber);
CLI11_PARSE(app, argc, argv); CLI11_PARSE(app, argc, argv);
console = spdlog::stdout_color_st(ident); console = spdlog::stdout_color_st(ident);
console->set_level(spdlog::level::from_str(log_level_option)); console->set_level(spdlog::level::from_str(log_level_option));
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, log_level_option);
log_level_option); console->info("Starting Boltzmann Wealth Model with {} agents on a {}x{}-unit grid for {} steps", agent_count, x_size, y_size, max_steps);
console->info(
"Starting Boltzmann Wealth Model with {} agents on a {}x{}-unit grid "
"for {} steps",
agent_count, x_size, y_size, max_steps);
BoltzmannWealthModel2D model(agent_count, x_size, y_size, initial_seed); BoltzmannWealthModel2D model(agent_count, x_size, y_size, initial_seed);
@@ -202,6 +177,5 @@ int main(int argc, char **argv) {
console->trace("Initiating model step {}", i); console->trace("Initiating model step {}", i);
model.step(); model.step();
} }
console->info( console->info("Boltzmann Wealth Model simulation complete, requiring {} seconds", sw);
"Boltzman Wealth Model simulation complete, requiring {} seconds", sw);
} }

View File

@@ -24,8 +24,8 @@
*/ */
#pragma once #pragma once
#ifndef BOLTZMAN2D_H #ifndef BOLTZMANN2D_H
#define BOLTZMAN2D_H #define BOLTZMANN2D_H
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/kami.h> #include <kami/kami.h>
@@ -42,7 +42,7 @@ using namespace std;
* A sample agent for a two-dimensional Boltzmann wealth model * A sample agent for a two-dimensional Boltzmann wealth model
*/ */
class MoneyAgent2D : public Agent { class MoneyAgent2D : public Agent {
public: public:
/** /**
* Create the agent * Create the agent
*/ */
@@ -51,7 +51,7 @@ class MoneyAgent2D : public Agent {
/** /**
* Execute a single time-step for the agent * Execute a single time-step for the agent
*/ */
void step(); void step() override;
/** /**
* Give the agent a reference copy of the domain it is expected to work in * Give the agent a reference copy of the domain it is expected to work in
@@ -68,22 +68,12 @@ class MoneyAgent2D : public Agent {
*/ */
void move_agent(); void move_agent();
/**
* Return the wealth of the agent
*/
int get_wealth();
/**
* Set the wealth of the agent
*/
void set_wealth(int wealth);
/** /**
* Give money to a random agent * Give money to a random agent
*/ */
void give_money(); void give_money();
private: private:
static MultiGrid2D *_world; static MultiGrid2D *_world;
static BoltzmannWealthModel2D *_model; static BoltzmannWealthModel2D *_model;
int _step_counter; int _step_counter;
@@ -94,9 +84,9 @@ class MoneyAgent2D : public Agent {
* The two-dimensional Boltzmann wealth model * The two-dimensional Boltzmann wealth model
*/ */
class BoltzmannWealthModel2D : public Model { class BoltzmannWealthModel2D : public Model {
public: public:
/** /**
* Create an instance of the two-dimensional Boltzman wealth model. * Create an instance of the two-dimensional Boltzmann wealth model.
* *
* @param[in] number_agents the number of agents to assign to the model. * @param[in] number_agents the number of agents to assign to the model.
* @param[in] length_x the length of the two-dimensional world the agents * @param[in] length_x the length of the two-dimensional world the agents
@@ -106,10 +96,7 @@ class BoltzmannWealthModel2D : public Model {
* @param[in] new_seed the initial seed used for the random number * @param[in] new_seed the initial seed used for the random number
* generator. * generator.
*/ */
BoltzmannWealthModel2D(unsigned int number_agents = 10, explicit BoltzmannWealthModel2D(unsigned int number_agents = 10, unsigned int length_x = 10, unsigned int length_y = 10, unsigned int new_seed = 42);
unsigned int length_x = 10,
unsigned int length_y = 10,
unsigned int new_seed = 42);
/** /**
* Destroy the instance * Destroy the instance
@@ -119,32 +106,27 @@ class BoltzmannWealthModel2D : public Model {
/** /**
* Execute a single time-step for the model. * Execute a single time-step for the model.
*/ */
void step(); void step() override;
/** /**
* Execute a number of time-steps for the model. * Execute a number of time-steps for the model.
* *
* @param[in] n the number of steps to execute. * @param[in] n the number of steps to execute.
*/ */
void run(unsigned int n); void run(unsigned int n) override;
/**
* Return the seed used to initialize the model.
*/
int get_seed() const;
/** /**
* Get the MoneyAgent2D instance associated with the given `AgentID` * Get the MoneyAgent2D instance associated with the given `AgentID`
* *
* @returns an pointer to the `MoneyAgent2D` that was requested. * @returns an pointer to the `MoneyAgent2D` that was requested.
*/ */
MoneyAgent2D *get_agent_by_id(AgentID agent_id) const; [[nodiscard]] MoneyAgent2D *get_agent_by_id(AgentID agent_id) const override;
private: private:
map<AgentID, MoneyAgent2D *> _agent_list; map<AgentID, MoneyAgent2D *> _agent_list;
RandomScheduler *_sched; RandomScheduler *_sched;
MultiGrid2D *_world; MultiGrid2D *_world;
unsigned int _step_count; unsigned int _step_count;
}; };
#endif // BOLTZMAN2D_H #endif // BOLTZMANN2D_H

View File

@@ -27,11 +27,12 @@
#ifndef KAMI_AGENT_H #ifndef KAMI_AGENT_H
#define KAMI_AGENT_H #define KAMI_AGENT_H
#include <kami/kami.h>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <kami/kami.h>
namespace kami { namespace kami {
/** /**
@@ -43,77 +44,77 @@ namespace kami {
* *
* @see Agent * @see Agent
*/ */
class LIBKAMI_EXPORT AgentID { class LIBKAMI_EXPORT AgentID {
public: public:
/** /**
* Constructs a new unique identifier. * Constructs a new unique identifier.
*/ */
AgentID() : _id(_id_next++){}; AgentID() : _id(_id_next++){};
/** /**
* Convert the identifier to a human-readable string. * Convert the identifier to a human-readable string.
* *
* @return a human-readable form of the `AgentID` as `std::string`. * @return a human-readable form of the `AgentID` as `std::string`.
*/ */
std::string to_string() const { return std::to_string(_id); } [[nodiscard]] std::string to_string() const { return std::to_string(_id); }
/** /**
* Test if two `AgentID` instances are equal. * Test if two `AgentID` instances are equal.
* *
* @param lhs is the left-hand side of the equality test. * @param lhs is the left-hand side of the equality test.
* @param rhs is the right-hand side of the equality test. * @param rhs is the right-hand side of the equality test.
* @return true is they are equal and false if not. * @return true is they are equal and false if not.
*/ */
friend bool operator==(const AgentID &lhs, const AgentID &rhs); friend bool operator==(const AgentID &lhs, const AgentID &rhs);
/** /**
* Test if two `AgentID` instances are not equal. * Test if two `AgentID` instances are not equal.
* *
* @param lhs is the left-hand side of the equality test. * @param lhs is the left-hand side of the equality test.
* @param rhs is the right-hand side of the equality test. * @param rhs is the right-hand side of the equality test.
* @return true is they are not equal and false if they are. * @return true is they are not equal and false if they are.
*/ */
friend bool operator!=(const AgentID &lhs, const AgentID &rhs); friend bool operator!=(const AgentID &lhs, const AgentID &rhs);
/** /**
* Test if one AgentID is less than another. * Test if one AgentID is less than another.
* *
* Due to the way AgentID instances are used internally, * Due to the way AgentID instances are used internally,
* the AgentID must be orderable. The `<` operator provides a * the AgentID must be orderable. The `<` operator provides a
* basic ordering sufficient for `std::map`. * basic ordering sufficient for `std::map`.
* *
* @param lhs is the left-hand side of the ordering test. * @param lhs is the left-hand side of the ordering test.
* @param rhs is the right-hand side of the ordering test. * @param rhs is the right-hand side of the ordering test.
* @return true if `lhs` is "less than" `rhs` as determined by the * @return true if `lhs` is "less than" `rhs` as determined by the
* underlying implementation of the `AgentID`. * underlying implementation of the `AgentID`.
*/ */
friend bool operator<(const AgentID &lhs, const AgentID &rhs); friend bool operator<(const AgentID &lhs, const AgentID &rhs);
/** /**
* Output an AgentID to the specified output stream * Output an AgentID to the specified output stream
* *
* The form of the output will be the same as that produced by the * The form of the output will be the same as that produced by the
* `to_string()` member function. * `to_string()` member function.
* *
* @param lhs is the stream to output the `AgentID` to * @param lhs is the stream to output the `AgentID` to
* @param rhs is the `AgentID` to output * @param rhs is the `AgentID` to output
* @return the output stream for reuse * @return the output stream for reuse
*/ */
friend std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs); friend std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs);
private: private:
inline static long long _id_next = 1; inline static long long _id_next = 1;
/** /**
* The unique identifier is a `long long`. * The unique identifier is a `long long`.
* *
* The unique identifier is an unsigned integer that increments * The unique identifier is an unsigned integer that increments
* monotonically with each new `AgentID` instantiated. This is * monotonically with each new `AgentID` instantiated. This is
* substantially faster than other potential identifiers, such * substantially faster than other potential identifiers, such
* as MD5 hashes or UUID objects. * as MD5 hashes or UUID objects.
*/ */
long long _id; long long _id;
}; };
/** /**
* A superclass for all agents. * A superclass for all agents.
@@ -124,58 +125,58 @@ class LIBKAMI_EXPORT AgentID {
* *
* @see `StagedAgent` * @see `StagedAgent`
*/ */
class LIBKAMI_EXPORT Agent { class LIBKAMI_EXPORT Agent {
public: public:
/** /**
* Get the `Agent`'s `AgentID`. * Get the `Agent`'s `AgentID`.
* *
* @return the `AgentID` * @return the `AgentID`
*/ */
AgentID get_agent_id() const; [[nodiscard]] AgentID get_agent_id() const;
/** /**
* Execute a time-step for the agent * Execute a time-step for the agent
* *
* This function should step the agent instance. Any activities that the * This function should step the agent instance. Any activities that the
* agent should perform as part of its time step should be in this function. * agent should perform as part of its time step should be in this function.
*/ */
virtual void step() = 0; virtual void step() = 0;
/** /**
* Compare if two `Agent`s are the same `Agent`. * Compare if two `Agent`s are the same `Agent`.
* *
* @param lhs is the left-hand side of the equality test. * @param lhs is the left-hand side of the equality test.
* @param rhs is the right-hand side of the equality test. * @param rhs is the right-hand side of the equality test.
* @return true is they are equal and false if not. * @return true is they are equal and false if not.
* *
* @note This does not compare that two Agent instances are * @note This does not compare that two Agent instances are
* identical. Accordingly, this can be used to compare two instances * identical. Accordingly, this can be used to compare two instances
* of the same Agent at different points in its time stream. * of the same Agent at different points in its time stream.
* *
* Subclasses of Agent may chose to extend this operator to tighten * Subclasses of Agent may chose to extend this operator to tighten
* the restrictioons on the comparison. * the restrictions on the comparison.
*/ */
friend bool operator==(const Agent &lhs, const Agent &rhs); friend bool operator==(const Agent &lhs, const Agent &rhs);
/** /**
* Compare if two `Agent`s are not the same `Agent`. * Compare if two `Agent`s are not the same `Agent`.
* *
* @param lhs is the left-hand side of the equality test. * @param lhs is the left-hand side of the equality test.
* @param rhs is the right-hand side of the equality test. * @param rhs is the right-hand side of the equality test.
* @return true is they are not equal and false if they are. * @return true is they are not equal and false if they are.
* *
* @note This does not compare that two Agent instances are * @note This does not compare that two Agent instances are
* identical. Accordingly, this can be used to compare two instances * identical. Accordingly, this can be used to compare two instances
* of the same `Agent` at different points in its time stream. * of the same `Agent` at different points in its time stream.
* *
* Subclasses of `Agent` may chose to extend this operator to tighten * Subclasses of `Agent` may chose to extend this operator to tighten
* the restrictioons on the comparison. * the restrictions on the comparison.
*/ */
friend bool operator!=(const Agent &lhs, const Agent &rhs); friend bool operator!=(const Agent &lhs, const Agent &rhs);
private: private:
const AgentID _agent_id; const AgentID _agent_id;
}; };
/** /**
* A superclass for all staged agents. * A superclass for all staged agents.
@@ -189,17 +190,17 @@ class LIBKAMI_EXPORT Agent {
* *
* `StagedAgents` must implement both the `step()` and `advance()` functions. * `StagedAgents` must implement both the `step()` and `advance()` functions.
*/ */
class LIBKAMI_EXPORT StagedAgent : public Agent { class LIBKAMI_EXPORT StagedAgent : public Agent {
public: public:
/** /**
* Post-step advance the agent * Post-step advance the agent
* *
* This method should be called after `step()`. Any updates or cleanups to * This method should be called after `step()`. Any updates or cleanups to
* the agent that must happen for the `StagedAgent` to complete its step must * the agent that must happen for the `StagedAgent` to complete its step must
* happen here. * happen here.
*/ */
virtual void advance() = 0; virtual void advance() = 0;
}; };
} // namespace kami } // namespace kami

View File

@@ -27,10 +27,10 @@
#ifndef KAMI_DOMAIN_H #ifndef KAMI_DOMAIN_H
#define KAMI_DOMAIN_H #define KAMI_DOMAIN_H
#include <kami/kami.h>
#include <string> #include <string>
#include <kami/kami.h>
namespace kami { namespace kami {
/** /**
@@ -38,7 +38,7 @@ namespace kami {
* *
* Implementations of virtual environments are expected to subclass `Domain`. * Implementations of virtual environments are expected to subclass `Domain`.
*/ */
class LIBKAMI_EXPORT Domain {}; class LIBKAMI_EXPORT Domain {};
/** /**
* Provides a coordinate system for each `Domain`. * Provides a coordinate system for each `Domain`.
@@ -52,27 +52,27 @@ class LIBKAMI_EXPORT Domain {};
* *
* @see GridCoord * @see GridCoord
*/ */
class LIBKAMI_EXPORT Coord { class LIBKAMI_EXPORT Coord {
public: public:
/** /**
* Convert the coordinate to a human-readable string. * Convert the coordinate to a human-readable string.
* *
* @return a human-readable form of the `Coord` as `std::string`. * @return a human-readable form of the `Coord` as `std::string`.
*/ */
virtual std::string to_string() const = 0; [[nodiscard]] virtual std::string to_string() const = 0;
/** /**
* Output a `Coord` to the specified output stream * Output a `Coord` to the specified output stream
* *
* The form of the output will be the same as that produced by the * The form of the output will be the same as that produced by the
* `to_string()` member function. * `to_string()` member function.
* *
* @param lhs is the stream to output the `Coord` to * @param lhs is the stream to output the `Coord` to
* @param rhs is the `Coord` to output * @param rhs is the `Coord` to output
* @return the output stream for reuse * @return the output stream for reuse
*/ */
friend std::ostream &operator<<(std::ostream &lhs, const Coord &rhs); friend std::ostream &operator<<(std::ostream &lhs, const Coord &rhs);
}; };
} // namespace kami } // namespace kami

View File

@@ -27,11 +27,11 @@
#ifndef KAMI_GRID_H #ifndef KAMI_GRID_H
#define KAMI_GRID_H #define KAMI_GRID_H
#include <string>
#include <kami/domain.h> #include <kami/domain.h>
#include <kami/kami.h> #include <kami/kami.h>
#include <string>
namespace kami { namespace kami {
/** /**
@@ -42,47 +42,47 @@ namespace kami {
* distinction between those neighborhoods that include those cells touching on * distinction between those neighborhoods that include those cells touching on
* the corners or diagonally and those neighborhoods that do not. * the corners or diagonally and those neighborhoods that do not.
*/ */
enum class GridNeighborhoodType { enum class GridNeighborhoodType {
/** /**
* @brief Moore neighborhood * @brief Moore neighborhood
* *
* @details Moore neighborhood types include diagonally-adjacent cells as * @details Moore neighborhood types include diagonally-adjacent cells as
* neighbors. * neighbors.
*/ */
Moore, Moore [[maybe_unused]],
/** /**
* @brief Von Neumann neighborhood * @brief Von Neumann neighborhood
* *
* @details Von Neumann neighborhood types do not include * @details Von Neumann neighborhood types do not include
* diagonally-adjacent cells as neighbors. * diagonally-adjacent cells as neighbors.
*/ */
VonNeumann VonNeumann [[maybe_unused]]
}; };
/** /**
* @brief Distance types for orthogonal grid domains * @brief Distance types for orthogonal grid domains
*/ */
enum class GridDistanceType { enum class GridDistanceType {
/** /**
* @brief Euclidean distance. * @brief Euclidean distance.
* *
* @details The Euclidean distance is the length of the line segment * @details The Euclidean distance is the length of the line segment
* connecting two points. This is commonly called a "beeline" or * connecting two points. This is commonly called a "beeline" or
* "as the crow flies." * "as the crow flies."
*/ */
Euclidean, Euclidean [[maybe_unused]],
/** /**
* @brief Manhattan distance. * @brief Manhattan distance.
* *
* @details The Manhattan distance is the sum of the absolute value of the * @details The Manhattan distance is the sum of the absolute value of the
* differences of the elements. This is commonly called the * differences of the elements. This is commonly called the
* "taxicab distance," "rectilinear distance," or many other [formal * "taxicab distance," "rectilinear distance," or many other [formal
* names](https://en.wikipedia.org/wiki/Taxicab_geometry). * names](https://en.wikipedia.org/wiki/Taxicab_geometry).
*/ */
Manhattan Manhattan [[maybe_unused]]
}; };
/** /**
* @brief An abstract domain based on a gridded environment. * @brief An abstract domain based on a gridded environment.
@@ -91,15 +91,15 @@ enum class GridDistanceType {
* rectilinear grid where the cells are equal size and laid out in an ordered * rectilinear grid where the cells are equal size and laid out in an ordered
* fashion. * fashion.
*/ */
class LIBKAMI_EXPORT GridDomain : public Domain {}; class LIBKAMI_EXPORT GridDomain : public Domain {};
/** /**
* @brief An abstract for gridded coordinates. * @brief An abstract for gridded coordinates.
* *
* @details All gridded coordinates are expected to subclass `GridCoord`. * @details All gridded coordinates are expected to subclass `GridCoord`.
*/ */
class LIBKAMI_EXPORT GridCoord : public Coord {}; class LIBKAMI_EXPORT GridCoord : public Coord {};
} // namespace kami } // namespace kami
#endif // KAMI_DOMAIN_H #endif // KAMI_GRID_H

View File

@@ -27,223 +27,221 @@
#ifndef KAMI_GRID1D_H #ifndef KAMI_GRID1D_H
#define KAMI_GRID1D_H #define KAMI_GRID1D_H
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/kami.h>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/kami.h>
namespace kami { namespace kami {
/** /**
* One-dimensional coordinates * One-dimensional coordinates
*/ */
class LIBKAMI_EXPORT GridCoord1D : public GridCoord { class LIBKAMI_EXPORT GridCoord1D : public GridCoord {
public: public:
/** /**
* Constructor for one-dimensional coordinates * Constructor for one-dimensional coordinates
*/ */
GridCoord1D(int x_coord) : _x_coord(x_coord){}; explicit GridCoord1D(int x_coord) : _x_coord(x_coord){};
/** /**
* Return the `x` coordinate * Return the `x` coordinate
*/ */
int get_x_location(void) const; [[nodiscard]] int get_x_location() const;
/** /**
* Convert the coordinate to a human-readable string. * Convert the coordinate to a human-readable string.
* *
* @return a human-readable form of the `Coord` as `std::string`. * @return a human-readable form of the `Coord` as `std::string`.
*/ */
std::string to_string() const; [[nodiscard]] std::string to_string() const override;
/** /**
* Test if two coordinates are equal * Test if two coordinates are equal
*/ */
friend bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs); friend bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs);
/** /**
* Test if two coordinates are not equal * Test if two coordinates are not equal
*/ */
friend bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs); friend bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs);
/** /**
* Output a given coordinate to the specified stream * Output a given coordinate to the specified stream
*/ */
friend std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs); friend std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs);
private: private:
int _x_coord; int _x_coord;
}; };
/** /**
* A one-dimensional grid where each cell may contain agents * A one-dimensional grid where each cell may contain agents
* *
* The grid is linear and may wrap around in its only dimension. * The grid is linear and may wrap around in its only dimension.
* *
* @see `MultiGrid1D` * @see `MultiGrid1D`
* @see `SoloGrid1D` * @see `SoloGrid1D`
*/ */
class LIBKAMI_EXPORT Grid1D : public GridDomain { class LIBKAMI_EXPORT Grid1D : public GridDomain {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid. * @param[in] maximum_x the length of the grid.
* @param[in] wrap_x should the grid wrap around on itself. * @param[in] wrap_x should the grid wrap around on itself.
*/ */
Grid1D(unsigned int maximum_x, bool wrap_x = false); explicit Grid1D(unsigned int maximum_x, bool wrap_x = false);
/** /**
* Deconstructor * Deconstructor
*/ */
virtual ~Grid1D(); virtual ~Grid1D();
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true. * location, otherwise, true.
*/ */
virtual bool add_agent(AgentID agent_id, GridCoord1D coord) = 0; virtual bool add_agent(AgentID agent_id, GridCoord1D coord) = 0;
/** /**
* Remove agent from the grid. * Remove agent from the grid.
* *
* @param[in] agent_id the `AgentID` of the agent to remove. * @param[in] agent_id the `AgentID` of the agent to remove.
* *
* @returns false if the agent is not removed, otherwise, true. * @returns false if the agent is not removed, otherwise, true.
*/ */
bool delete_agent(AgentID agent_id); [[maybe_unused]] [[maybe_unused]] bool delete_agent(AgentID agent_id);
/** /**
* Remove agent from the grid at the specified location * Remove agent from the grid at the specified location
* *
* @param[in] agent_id the `AgentID` of the agent to remove. * @param[in] agent_id the `AgentID` of the agent to remove.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not removed, otherwise, true. * @returns false if the agent is not removed, otherwise, true.
*/ */
virtual bool delete_agent(AgentID agent_id, GridCoord1D coord); bool delete_agent(AgentID agent_id, const GridCoord1D &coord);
/** /**
* Move an agent to the specified location. * Move an agent to the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to move. * @param[in] agent_id the `AgentID` of the agent to move.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
*/ */
bool move_agent(AgentID agent_id, GridCoord1D coord); bool move_agent(AgentID agent_id, GridCoord1D coord);
/** /**
* Inquire if the specified location is empty. * Inquire if the specified location is empty.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return true if the location has no `Agent`s occupying it, false * @return true if the location has no `Agent`s occupying it, false
* otherwise. * otherwise.
*/ */
bool is_location_empty(GridCoord1D coord) const; [[nodiscard]] bool is_location_empty(const GridCoord1D& coord) const;
/** /**
* Inquire if the specified location is valid within the grid. * Inquire if the specified location is valid within the grid.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return true if the location specified is valid, false otherwise. * @return true if the location specified is valid, false otherwise.
*/ */
bool is_location_valid(GridCoord1D coord) const; [[nodiscard]] bool is_location_valid(const GridCoord1D& coord) const;
/** /**
* Get the location of the specified agent. * Get the location of the specified agent.
* *
* @param[in] agent_id the `AgentID` of the agent in question. * @param[in] agent_id the `AgentID` of the agent in question.
* *
* @return the location of the specified `Agent` * @return the location of the specified `Agent`
*/ */
GridCoord1D get_location_by_agent(AgentID agent_id) const; [[nodiscard]] GridCoord1D get_location_by_agent(AgentID agent_id) const;
/** /**
* Get the contents of the specified location. * Get the contents of the specified location.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the * @return a pointer to a `vector` of `AgentID`s. The pointer is to the
* internal copy of the agent list at the location, therefore, any changes * internal copy of the agent list at the location, therefore, any changes
* to that object will update the state of the gird. Further, the pointer * to that object will update the state of the gird. Further, the pointer
* should not be deleted when no longer used. * should not be deleted when no longer used.
*/ */
std::vector<AgentID> *get_location_contents(GridCoord1D coord) const; [[nodiscard]] std::vector<AgentID> *get_location_contents(const GridCoord1D& coord) const;
/** /**
* Inquire to whether the grid wraps in the `x` dimension. * Inquire to whether the grid wraps in the `x` dimension.
* *
* @return true if the grid wraps, and false otherwise * @return true if the grid wraps, and false otherwise
*/ */
bool get_wrap_x(void) const; [[maybe_unused]] [[maybe_unused]] [[nodiscard]] bool get_wrap_x() const;
/** /**
* Return the neighborhood of the specified Agent * Return the neighborhood of the specified Agent
* *
* @param[in] agent_id the `AgentID` of the agent in question * @param[in] agent_id the `AgentID` of the agent in question
* @param[in] include_center should the center-point, occupied by the agent, * @param[in] include_center should the center-point, occupied by the agent,
* be in the list. * be in the list.
* *
* @return a vector of `GridCoord1D` that includes all of the coordinates * @return a vector of `GridCoord1D` that includes all of the coordinates
* for all adjacent points. * for all adjacent points.
*/ */
std::vector<GridCoord1D> get_neighborhood(AgentID agent_id, [[nodiscard]] std::vector<GridCoord1D> get_neighborhood(AgentID agent_id, bool include_center) const;
bool include_center) const;
/** /**
* Return the neighborhood of the specified location * Return the neighborhood of the specified location
* *
* @param[in] coord the coordinates of the specified location. * @param[in] coord the coordinates of the specified location.
* @param[in] include_center should the center-point, occupied by the agent, * @param[in] include_center should the center-point, occupied by the agent,
* be in the list. * be in the list.
* *
* @return a vector of `GridCoord1D` that includes all of the coordinates * @return a vector of `GridCoord1D` that includes all of the coordinates
* for all adjacent points. * for all adjacent points.
*/ */
std::vector<GridCoord1D> get_neighborhood(GridCoord1D coord, [[nodiscard]] std::vector<GridCoord1D> get_neighborhood(const GridCoord1D& coord, bool include_center) const;
bool include_center) const;
/** /**
* Get the size of the grid in the `x` dimension. * Get the size of the grid in the `x` dimension.
* *
* @return the length of the grid in the `x` dimension * @return the length of the grid in the `x` dimension
*/ */
unsigned int get_maximum_x(void) const; [[maybe_unused]] [[nodiscard]] unsigned int get_maximum_x() const;
protected: protected:
/** /**
* A vector containing the `AgentID`s of all agents assgined to this * A vector containing the `AgentID`s of all agents assigned to this
* grid. * grid.
*/ */
std::vector<AgentID> *_agent_grid; std::vector<AgentID> *_agent_grid;
/** /**
* A map containing the grid location of each agent. * A map containing the grid location of each agent.
*/ */
std::map<AgentID, GridCoord1D> *_agent_index; std::map<AgentID, GridCoord1D> *_agent_index;
/** /**
* Automatically adjust a coordinate location for wrapping. * Automatically adjust a coordinate location for wrapping.
* *
* @param[in] coord the coordinates of the specified location. * @param[in] coord the coordinates of the specified location.
* *
* @return the adjusted coordinate wrapped if appropriate. * @return the adjusted coordinate wrapped if appropriate.
*/ */
GridCoord1D coord_wrap(GridCoord1D coord) const; [[nodiscard]] GridCoord1D coord_wrap(const GridCoord1D& coord) const;
private: private:
unsigned int _maximum_x; unsigned int _maximum_x;
bool _wrap_x; bool _wrap_x;
}; };
} // namespace kami } // namespace kami

View File

@@ -27,62 +27,62 @@
#ifndef KAMI_GRID2D_H #ifndef KAMI_GRID2D_H
#define KAMI_GRID2D_H #define KAMI_GRID2D_H
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/kami.h>
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <vector> #include <vector>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/kami.h>
namespace kami { namespace kami {
/** /**
* Two-dimensional coordinates * Two-dimensional coordinates
*/ */
class LIBKAMI_EXPORT GridCoord2D : public GridCoord { class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
public: public:
/** /**
* Constructor for two-dimensional coordinates * Constructor for two-dimensional coordinates
*/ */
GridCoord2D(int x_coord, int y_coord) GridCoord2D(int x_coord, int y_coord)
: _x_coord(x_coord), _y_coord(y_coord){}; : _x_coord(x_coord), _y_coord(y_coord){};
/** /**
* Get the coordinate in the first dimension or `x`. * Get the coordinate in the first dimension or `x`.
*/ */
int get_x_location(void) const; [[nodiscard]] int get_x_location() const;
/** /**
* Get the coordinate in the second dimension or `y`. * Get the coordinate in the second dimension or `y`.
*/ */
int get_y_location(void) const; [[nodiscard]] int get_y_location() const;
/** /**
* Convert the coordinate to a human-readable string. * Convert the coordinate to a human-readable string.
* *
* @return a human-readable form of the `Coord` as `std::string`. * @return a human-readable form of the `Coord` as `std::string`.
*/ */
std::string to_string() const; [[nodiscard]] std::string to_string() const override;
/** /**
* Test if two coordinates are equal * Test if two coordinates are equal
*/ */
friend bool operator==(const GridCoord2D &, const GridCoord2D &); friend bool operator==(const GridCoord2D &, const GridCoord2D &);
/** /**
* Test if two coordinates are not equal * Test if two coordinates are not equal
*/ */
friend bool operator!=(const GridCoord2D &, const GridCoord2D &); friend bool operator!=(const GridCoord2D &, const GridCoord2D &);
/** /**
* Output a given coordinate to the specified stream * Output a given coordinate to the specified stream
*/ */
friend std::ostream &operator<<(std::ostream &, const GridCoord2D &); friend std::ostream &operator<<(std::ostream &, const GridCoord2D &);
private: private:
int _x_coord, _y_coord; int _x_coord, _y_coord;
}; };
/** /**
* A two-dimensional grid where each cell may contain agents * A two-dimensional grid where each cell may contain agents
@@ -92,191 +92,187 @@ class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
* @see `MultiGrid2D` * @see `MultiGrid2D`
* @see `SoloGrid2D` * @see `SoloGrid2D`
*/ */
class LIBKAMI_EXPORT Grid2D : public GridDomain { class LIBKAMI_EXPORT Grid2D : public GridDomain {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid in the first dimension * @param[in] maximum_x the length of the grid in the first dimension
* @param[in] maximum_y the length of the grid in the second dimension * @param[in] maximum_y the length of the grid in the second dimension
* @param[in] wrap_x should the grid wrap around on itself in the first * @param[in] wrap_x should the grid wrap around on itself in the first
* dimension * dimension
* @param[in] wrap_y should the grid wrap around on itself in the second * @param[in] wrap_y should the grid wrap around on itself in the second
* dimension * dimension
*/ */
Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x = false, Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x = false,
bool wrap_y = false); bool wrap_y = false);
/** /**
* Deconstructor * Deconstructor
*/ */
virtual ~Grid2D(); virtual ~Grid2D();
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true. * location, otherwise, true.
*/ */
virtual bool add_agent(AgentID agent_id, GridCoord2D coord) = 0; virtual bool add_agent(AgentID agent_id, GridCoord2D coord) = 0;
/** /**
* Remove agent from the grid. * Remove agent from the grid.
* *
* @param[in] agent_id the `AgentID` of the agent to remove. * @param[in] agent_id the `AgentID` of the agent to remove.
* *
* @returns false if the agent is not removed, otherwise, true. * @returns false if the agent is not removed, otherwise, true.
*/ */
bool delete_agent(AgentID agent_id); [[maybe_unused]] bool delete_agent(AgentID agent_id);
/** /**
* Remove agent from the grid at the specified location * Remove agent from the grid at the specified location
* *
* @param[in] agent_id the `AgentID` of the agent to remove. * @param[in] agent_id the `AgentID` of the agent to remove.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not removed, otherwise, true. * @returns false if the agent is not removed, otherwise, true.
*/ */
virtual bool delete_agent(AgentID agent_id, GridCoord2D coord); bool delete_agent(AgentID agent_id, const GridCoord2D &coord);
/** /**
* Move an agent to the specified location. * Move an agent to the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to move. * @param[in] agent_id the `AgentID` of the agent to move.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
*/ */
bool move_agent(AgentID agent_id, GridCoord2D coord); bool move_agent(AgentID agent_id, GridCoord2D coord);
/** /**
* Inquire if the specified location is empty. * Inquire if the specified location is empty.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return true if the location has no `Agent`s occupying it, false * @return true if the location has no `Agent`s occupying it, false
* otherwise. * otherwise.
*/ */
bool is_location_empty(GridCoord2D coord) const; [[nodiscard]] bool is_location_empty(const GridCoord2D& coord) const;
/** /**
* Inquire if the specified location is valid within the grid. * Inquire if the specified location is valid within the grid.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return true if the location specified is valid, false otherwise. * @return true if the location specified is valid, false otherwise.
*/ */
bool is_location_valid(GridCoord2D coord) const; [[nodiscard]] bool is_location_valid(const GridCoord2D& coord) const;
/** /**
* Get the location of the specified agent. * Get the location of the specified agent.
* *
* @param[in] agent_id the `AgentID` of the agent in question. * @param[in] agent_id the `AgentID` of the agent in question.
* *
* @return the location of the specified `Agent` * @return the location of the specified `Agent`
*/ */
GridCoord2D get_location_by_agent(AgentID agent_id) const; [[nodiscard]] GridCoord2D get_location_by_agent(AgentID agent_id) const;
/** /**
* Get the contents of the specified location. * Get the contents of the specified location.
* *
* @param[in] coord the coordinates of the query. * @param[in] coord the coordinates of the query.
* *
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the * @return a pointer to a `vector` of `AgentID`s. The pointer is to the
* internal copy of the agent list at the location, therefore, any changes * internal copy of the agent list at the location, therefore, any changes
* to that object will update the state of the gird. Further, the pointer * to that object will update the state of the gird. Further, the pointer
* should not be deleted when no longer used. * should not be deleted when no longer used.
*/ */
std::vector<AgentID> *get_location_contents(GridCoord2D coord) const; [[nodiscard]] std::vector<AgentID> *get_location_contents(const GridCoord2D& coord) const;
/** /**
* Inquire to whether the grid wraps in the `x` dimension. * Inquire to whether the grid wraps in the `x` dimension.
* *
* @return true if the grid wraps, and false otherwise * @return true if the grid wraps, and false otherwise
*/ */
bool get_wrap_x(void) const; [[maybe_unused]] [[nodiscard]] bool get_wrap_x() const;
/** /**
* Inquire to whether the grid wraps in the `y` dimension. * Inquire to whether the grid wraps in the `y` dimension.
* *
* @return true if the grid wraps, and false otherwise * @return true if the grid wraps, and false otherwise
*/ */
bool get_wrap_y(void) const; [[maybe_unused]] [[nodiscard]] bool get_wrap_y() const;
/** /**
* Return the neighborhood of the specified Agent * Return the neighborhood of the specified Agent
* *
* @param[in] agent_id the `AgentID` of the agent in question. * @param[in] agent_id the `AgentID` of the agent in question.
* @param[in] neighborhood_type the neighborhood type. * @param[in] neighborhood_type the neighborhood type.
* @param[in] include_center should the center-point, occupied by the agent, * @param[in] include_center should the center-point, occupied by the agent,
* be in the list. * be in the list.
* *
* @return a vector of `GridCoord1D` that includes all of the coordinates * @return a vector of `GridCoord1D` that includes all of the coordinates
* for all adjacent points. * for all adjacent points.
* *
* @see `NeighborhoodType` * @see `NeighborhoodType`
*/ */
std::vector<GridCoord2D> get_neighborhood( [[nodiscard]] std::vector<GridCoord2D> get_neighborhood(AgentID agent_id, GridNeighborhoodType neighborhood_type, bool include_center) const;
AgentID agent_id, GridNeighborhoodType neighborhood_type,
bool include_center) const;
/** /**
* Return the neighborhood of the specified location * Return the neighborhood of the specified location
* *
* @param[in] coord the coordinates of the specified location. * @param[in] coord the coordinates of the specified location.
* @param[in] neighborhood_type the neighborhood type. * @param[in] neighborhood_type the neighborhood type.
* @param[in] include_center should the center-point, occupied by the agent, * @param[in] include_center should the center-point, occupied by the agent,
* be in the list. * be in the list.
* *
* @return a vector of `GridCoord1D` that includes all of the coordinates * @return a vector of `GridCoord1D` that includes all of the coordinates
* for all adjacent points. * for all adjacent points.
* *
* @see `NeighborhoodType` * @see `NeighborhoodType`
*/ */
std::vector<GridCoord2D> get_neighborhood( [[nodiscard]] std::vector<GridCoord2D> get_neighborhood(const GridCoord2D& coord, GridNeighborhoodType neighborhood_type, bool include_center) const;
GridCoord2D coord, GridNeighborhoodType neighborhood_type,
bool include_center) const;
/** /**
* Get the size of the grid in the `x` dimension. * Get the size of the grid in the `x` dimension.
* *
* @return the length of the grid in the `x` dimension * @return the length of the grid in the `x` dimension
*/ */
unsigned int get_maximum_x(void) const; [[maybe_unused]] [[nodiscard]] unsigned int get_maximum_x() const;
/** /**
* Get the size of the grid in the `y` dimension. * Get the size of the grid in the `y` dimension.
* *
* @return the length of the grid in the `xy dimension * @return the length of the grid in the `xy dimension
*/ */
unsigned int get_maximum_y(void) const; [[maybe_unused]] [[nodiscard]] unsigned int get_maximum_y() const;
protected: protected:
/** /**
* A vector containing the `AgentID`s of all agents assgined to this * A vector containing the `AgentID`s of all agents assigned to this
* grid. * grid.
*/ */
std::vector<AgentID> **_agent_grid; std::vector<AgentID> **_agent_grid;
/** /**
* A map containing the grid location of each agent. * A map containing the grid location of each agent.
*/ */
std::map<AgentID, GridCoord2D> *_agent_index; std::map<AgentID, GridCoord2D> *_agent_index;
/** /**
* Automatically adjust a coordinate location for wrapping. * Automatically adjust a coordinate location for wrapping.
* *
* @param[in] coord the coordinates of the specified location. * @param[in] coord the coordinates of the specified location.
* *
* @return the adjusted coordinate wrapped if appropriate. * @return the adjusted coordinate wrapped if appropriate.
*/ */
GridCoord2D coord_wrap(GridCoord2D coord) const; [[nodiscard]] GridCoord2D coord_wrap(const GridCoord2D& coord) const;
private: private:
unsigned int _maximum_x, _maximum_y; unsigned int _maximum_x, _maximum_y;
bool _wrap_x, _wrap_y; bool _wrap_x, _wrap_y;
}; };
} // namespace kami } // namespace kami

View File

@@ -35,34 +35,34 @@ namespace kami {
/** /**
* An abstract for generic models * An abstract for generic models
*/ */
class LIBKAMI_EXPORT Model { class LIBKAMI_EXPORT Model {
public: public:
/** /**
* Get a reference to an `Agent` by `AgentID` * Get a reference to an `Agent` by `AgentID`
* *
* @param[in] agent_id the `AgentID` to search for. * @param[in] agent_id the `AgentID` to search for.
* *
* @return a reference to the desired `Agent` or `nullptr` if not found. * @return a reference to the desired `Agent` or `nullptr` if not found.
*/ */
virtual Agent *get_agent_by_id(AgentID agent_id) const = 0; [[nodiscard]] virtual Agent *get_agent_by_id(AgentID agent_id) const = 0;
/** /**
* Execute a fixed number of time-steps for the model. * Execute a fixed number of time-steps for the model.
* *
* This function should execute a fixed number of time-steps for the model. * This function should execute a fixed number of time-steps for the model.
* *
* @param[in] n the number of time steps to execute. * @param[in] n the number of time steps to execute.
*/ */
virtual void run(unsigned int n) = 0; [[maybe_unused]] virtual void run(unsigned int n) = 0;
/** /**
* Execute a single time-step for the model. * Execute a single time-step for the model.
* *
* This function should step the model instance. Any activities that the * This function should step the model instance. Any activities that the
* model should perform as part of its time step should be in this function. * model should perform as part of its time step should be in this function.
*/ */
virtual void step() = 0; virtual void step() = 0;
}; };
} // namespace kami } // namespace kami

View File

@@ -40,28 +40,28 @@ namespace kami {
* *
* @details The grid is linear and may wrap around in its only dimension. * @details The grid is linear and may wrap around in its only dimension.
*/ */
class LIBKAMI_EXPORT MultiGrid1D : public Grid1D { class LIBKAMI_EXPORT MultiGrid1D : public Grid1D {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid. * @param[in] maximum_x the length of the grid.
* @param[in] wrap_x should the grid wrap around on itself. * @param[in] wrap_x should the grid wrap around on itself.
*/ */
MultiGrid1D(unsigned int maximum_x, bool wrap_x) MultiGrid1D(unsigned int maximum_x, bool wrap_x)
: Grid1D(maximum_x, wrap_x) {} : Grid1D(maximum_x, wrap_x) {}
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true * location, otherwise, true
*/ */
bool add_agent(AgentID agent_id, GridCoord1D coord); bool add_agent(AgentID agent_id, GridCoord1D coord) override;
}; };
} // namespace kami } // namespace kami

View File

@@ -43,32 +43,32 @@ namespace kami {
* @see `Grid2D` * @see `Grid2D`
* @see `SoloGrid2D` * @see `SoloGrid2D`
*/ */
class LIBKAMI_EXPORT MultiGrid2D : public Grid2D { class LIBKAMI_EXPORT MultiGrid2D : public Grid2D {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid in the first dimension * @param[in] maximum_x the length of the grid in the first dimension
* @param[in] maximum_y the length of the grid in the second dimension * @param[in] maximum_y the length of the grid in the second dimension
* @param[in] wrap_x should the grid wrap around on itself in the first * @param[in] wrap_x should the grid wrap around on itself in the first
* dimension * dimension
* @param[in] wrap_y should the grid wrap around on itself in the second * @param[in] wrap_y should the grid wrap around on itself in the second
* dimension * dimension
*/ */
MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y)
bool wrap_y); : Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {};
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true * location, otherwise, true
*/ */
bool add_agent(AgentID agent_id, GridCoord2D coord); bool add_agent(AgentID agent_id, GridCoord2D coord) override;
}; };
} // namespace kami } // namespace kami

View File

@@ -47,62 +47,50 @@ namespace kami {
* *
* @note First create a Model for the scheduler to live in. * @note First create a Model for the scheduler to live in.
*/ */
class LIBKAMI_EXPORT RandomScheduler : public SequentialScheduler { class LIBKAMI_EXPORT RandomScheduler : public SequentialScheduler {
public: public:
/** /**
* @brief Constructor. * @brief Constructor.
* *
* @details The `model` parameter is used by the scheduler to get * @details The `model` parameter is used by the scheduler to get
* access to an `Agent`. The `Model` is presumed to maintain a master * access to an `Agent`. The `Model` is presumed to maintain a master
* list of all `Agent`s in the `Model` and the `Model` can be queried for * list of all `Agent`s in the `Model` and the `Model` can be queried for
* a reference to any particular `Agent` at `step()` time. * a reference to any particular `Agent` at `step()` time.
* *
* @param model [in] A reference to the model the scheduler is timing. * @param model [in] A reference to the model the scheduler is timing.
*/ * @param rng [in] A uniform random number generator of type
RandomScheduler(Model *model); * `std::mt19937`, used as the source of randomness.
*/
RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng);
/** /**
* @brief Constructor. * @brief Execute a single time step.
* *
* @details The `model` parameter is used by the scheduler to get * @details This method will randomize the list of Agents in the scheduler's
* access to an `Agent`. The `Model` is presumed to maintain a master * internal queue and then execute the `Agent::step()` method for every
* list of all `Agent`s in the `Model` and the `Model` can be queried for * Agent assigned to this scheduler in the randomized order.
* a reference to any particular `Agent` at `step()` time. */
* void step() override;
* @param model [in] A reference to the model the scheduler is timing.
* @param rng [in] A uniform random number generator of type
* `std::mt19937`, used as the source of randomness.
*/
RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng);
/** /**
* @brief Execute a single time step. * Set the random number generator used to randomize the order of agent
* * stepping.
* @details This method will randomize the list of Agents in the scheduler's *
* internal queue and then execute the `Agent::step()` method for every * @param rng [in] A uniform random number generator of type `std::mt19937`,
* Agent assigned to this scheduler in the randomized order. * used as the source of randomness.
*/ */
void step(); void set_rng(std::shared_ptr<std::mt19937> rng);
/** /**
* Set the random number generator used to randomize the order of agent * Get a reference to the random number generator used to randomize
* stepping. * the order of agent stepping.
* */
* @param rng [in] A uniform random number generator of type `std::mt19937`, [[maybe_unused]] std::shared_ptr<std::mt19937> get_rng();
* used as the source of randomness.
*/
void set_rng(std::shared_ptr<std::mt19937> rng);
/** private:
* Get a reference to the random number generator used to randomize std::shared_ptr<std::mt19937> _rng;
* the order of agent stepping. };
*/
std::shared_ptr<std::mt19937> get_rng();
private: } // namespace kami
std::shared_ptr<std::mt19937> _rng;
};
}; // namespace kami
#endif // KAMI_RANDOM_H #endif // KAMI_RANDOM_H

View File

@@ -39,29 +39,29 @@ namespace kami {
* scheduler will have a collection of agents assigned to it and will execute * scheduler will have a collection of agents assigned to it and will execute
* the step function for each agent based on the type of scheduling implemented. * the step function for each agent based on the type of scheduling implemented.
*/ */
class LIBKAMI_EXPORT Scheduler { class LIBKAMI_EXPORT Scheduler {
public: public:
/** /**
* Add an Agent to the Scheduler. * Add an Agent to the Scheduler.
* *
* @param agent_id The AgentID of the agent to add. * @param agent_id The AgentID of the agent to add.
*/ */
virtual void add_agent(AgentID agent_id) = 0; virtual void add_agent(AgentID agent_id) = 0;
/** /**
* Remove an Agent from the Scheduler. * Remove an Agent from the Scheduler.
* *
* @param agent_id The AgentID of the agent to remove. * @param agent_id The AgentID of the agent to remove.
*/ */
virtual void delete_agent(AgentID agent_id) = 0; [[maybe_unused]] virtual void delete_agent(AgentID agent_id) = 0;
/** /**
* Step the Scheduler. * Step the Scheduler.
* *
* A generic step function that executes a single time step. * A generic step function that executes a single time step.
*/ */
virtual void step() = 0; virtual void step() = 0;
}; };
} // namespace kami } // namespace kami

View File

@@ -27,14 +27,14 @@
#ifndef KAMI_SEQUENTIAL_H #ifndef KAMI_SEQUENTIAL_H
#define KAMI_SEQUENTIAL_H #define KAMI_SEQUENTIAL_H
#include <algorithm>
#include <vector>
#include <kami/KAMI_EXPORT.h> #include <kami/KAMI_EXPORT.h>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/model.h> #include <kami/model.h>
#include <kami/scheduler.h> #include <kami/scheduler.h>
#include <algorithm>
#include <vector>
namespace kami { namespace kami {
/** /**
@@ -47,62 +47,62 @@ namespace kami {
* *
* \pre First create a Model for the scheduler to live in. * \pre First create a Model for the scheduler to live in.
*/ */
class LIBKAMI_EXPORT SequentialScheduler : public Scheduler { class LIBKAMI_EXPORT SequentialScheduler : public Scheduler {
public: public:
/** /**
* @brief Constructor. * @brief Constructor.
* *
* @details The Model parameter is used by the scheduler to get * @details The Model parameter is used by the scheduler to get
* access to an Agent. The Model is presumed to maintain a master * access to an Agent. The Model is presumed to maintain a master
* list of all Agents in the Model and the Model can be queried for * list of all Agents in the Model and the Model can be queried for
* a reference to any particular Agent at `step()` time. * a reference to any particular Agent at `step()` time.
*/ */
SequentialScheduler(Model *model); explicit SequentialScheduler(Model *model);
/** /**
* @brief Add an agent to the scheduler. * @brief Add an agent to the scheduler.
* *
* @details The scheduler maintains a list of all AgentIDs currently * @details The scheduler maintains a list of all AgentIDs currently
* assigned. This function adds a new Agent to the list. * assigned. This function adds a new Agent to the list.
*/ */
void add_agent(AgentID agent_id); void add_agent(AgentID agent_id) override;
/** /**
* @brief Remove an agent from the scheduler. * @brief Remove an agent from the scheduler.
* *
* @details The scheduler maintains a list of all AgentIDs currently * @details The scheduler maintains a list of all AgentIDs currently
* assigned. This function removes an Agent from the list. * assigned. This function removes an Agent from the list.
*/ */
void delete_agent(AgentID agent_id); void delete_agent(AgentID agent_id) override;
/** /**
* @brief Execute a single time step. * @brief Execute a single time step.
* *
* @details This method will step through the list of Agents in the * @details This method will step through the list of Agents in the
* scheduler's internal queue and then execute the `Agent::step()` * scheduler's internal queue and then execute the `Agent::step()`
* method for every Agent assigned to this scheduler in the order * method for every Agent assigned to this scheduler in the order
* assigned. * assigned.
*/ */
void step(); void step() override;
protected: protected:
/** /**
* A vector containing the `AgentID`s of all agents assgined to this * A vector containing the `AgentID`s of all agents assigned to this
* scheduler * scheduler
*/ */
std::vector<AgentID> _agent_list; std::vector<AgentID> _agent_list;
/** /**
* A pointer to the `Model` this scehduler belongs to * A pointer to the `Model` this scheduler belongs to
*/ */
Model *_model; Model *_model;
/** /**
* Counter to increment on each step * Counter to increment on each step
*/ */
int _step_counter; int _step_counter;
}; };
}; // namespace kami } // namespace kami
#endif // KAMI_SEQUENTIAL_H #endif // KAMI_SEQUENTIAL_H

View File

@@ -29,8 +29,6 @@
#include <kami/KAMI_EXPORT.h> #include <kami/KAMI_EXPORT.h>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid1d.h> #include <kami/grid1d.h>
#include <kami/kami.h> #include <kami/kami.h>
@@ -41,28 +39,28 @@ namespace kami {
* *
* @details The grid is linear and may wrap around in its only dimension. * @details The grid is linear and may wrap around in its only dimension.
*/ */
class LIBKAMI_EXPORT SoloGrid1D : public Grid1D { class LIBKAMI_EXPORT SoloGrid1D : public Grid1D {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid. * @param[in] maximum_x the length of the grid.
* @param[in] wrap_x should the grid wrap around on itself. * @param[in] wrap_x should the grid wrap around on itself.
*/ */
SoloGrid1D(unsigned int maximum_x, bool wrap_x) SoloGrid1D(unsigned int maximum_x, bool wrap_x)
: Grid1D(maximum_x, wrap_x) {} : Grid1D(maximum_x, wrap_x) {}
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true * location, otherwise, true
*/ */
bool add_agent(AgentID agent_id, GridCoord1D coord); bool add_agent(AgentID agent_id, GridCoord1D coord) override;
}; };
} // namespace kami } // namespace kami

View File

@@ -27,14 +27,11 @@
#ifndef KAMI_SOLOGRID2D_H #ifndef KAMI_SOLOGRID2D_H
#define KAMI_SOLOGRID2D_H #define KAMI_SOLOGRID2D_H
#include <kami/KAMI_EXPORT.h>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid2d.h> #include <kami/grid2d.h>
#include <kami/kami.h> #include <kami/kami.h>
#include <vector>
namespace kami { namespace kami {
/** /**
@@ -45,30 +42,30 @@ namespace kami {
* @see `MultiGrid2D` * @see `MultiGrid2D`
* @see `Grid2D` * @see `Grid2D`
*/ */
class LIBKAMI_EXPORT SoloGrid2D : public Grid2D { class LIBKAMI_EXPORT SoloGrid2D : public Grid2D {
public: public:
/** /**
* Constructor * Constructor
* *
* @param[in] maximum_x the length of the grid in the first dimension * @param[in] maximum_x the length of the grid in the first dimension
* @param[in] maximum_y the length of the grid in the second dimension * @param[in] maximum_y the length of the grid in the second dimension
* @param[in] wrap_x should the grid wrap around on itself in the first dimension * @param[in] wrap_x should the grid wrap around on itself in the first dimension
* @param[in] wrap_y should the grid wrap around on itself in the second dimension * @param[in] wrap_y should the grid wrap around on itself in the second dimension
*/ */
SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y)
bool wrap_y); : Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {};
/** /**
* Place agent on the grid at the specified location. * Place agent on the grid at the specified location.
* *
* @param[in] agent_id the `AgentID` of the agent to add. * @param[in] agent_id the `AgentID` of the agent to add.
* @param[in] coord the coordinates of the agent. * @param[in] coord the coordinates of the agent.
* *
* @returns false if the agent is not placed at the specified * @returns false if the agent is not placed at the specified
* location, otherwise, true * location, otherwise, true
*/ */
bool add_agent(AgentID agent_id, GridCoord2D coord); bool add_agent(AgentID agent_id, GridCoord2D coord) override;
}; };
} // namespace kami } // namespace kami

View File

@@ -46,54 +46,54 @@ namespace kami {
* *
* @note First create a Model for the scheduler to live in. * @note First create a Model for the scheduler to live in.
*/ */
class LIBKAMI_EXPORT StagedScheduler : public Scheduler { class LIBKAMI_EXPORT StagedScheduler : public Scheduler {
public: public:
/** /**
* Constructor. * Constructor.
* The Model parameter is used by the scheduler to get access to an Agent. * The Model parameter is used by the scheduler to get access to an Agent.
* The Model is presumed to maintain a master list of all Agents in the * The Model is presumed to maintain a master list of all Agents in the
* Model and the Model can be queried for a reference to any particular * Model and the Model can be queried for a reference to any particular
* Agent at `step()` time. * Agent at `step()` time.
*/ */
StagedScheduler(Model *); explicit StagedScheduler(Model *);
/** /**
* A deconstructor. * A deconstructor.
*/ */
virtual ~StagedScheduler(); ~StagedScheduler() = default;
/** /**
* Add an agent to the scheduler. * Add an agent to the scheduler.
* *
* The scheduler maintains a list of all AgentIDs currently assigned. This * The scheduler maintains a list of all AgentIDs currently assigned. This
* function adds a new Agent to the list. * function adds a new Agent to the list.
*/ */
void add_agent(AgentID agent_id); void add_agent(AgentID agent_id) override;
/** /**
* Remove an agent from the scheduler. * Remove an agent from the scheduler.
* *
* The scheduler maintains a list of all AgentIDs currently assigned. This * The scheduler maintains a list of all AgentIDs currently assigned. This
* function removes an Agent from the list. * function removes an Agent from the list.
*/ */
void delete_agent(AgentID agent_id); void delete_agent(AgentID agent_id) override;
/** /**
* Execute a single time step. * Execute a single time step.
* *
* This method will step through the list of Agents in the scheduler's * This method will step through the list of Agents in the scheduler's
* internal queue and execute the `Agent::step()` method for each `Agent` * internal queue and execute the `Agent::step()` method for each `Agent`
* in the same order. Finally, it will execute the `Agent::advance()` * in the same order. Finally, it will execute the `Agent::advance()`
* method for each Agent in the same order. * method for each Agent in the same order.
*/ */
void step(); void step() override;
private: private:
std::vector<AgentID> _agent_list; std::vector<AgentID> _agent_list;
Model *_model; Model *_model;
int _step_counter; int _step_counter;
}; };
}; // namespace kami } // namespace kami
#endif // KAMI_STAGED_H #endif // KAMI_STAGED_H

View File

@@ -30,28 +30,28 @@
namespace kami { namespace kami {
bool operator==(const AgentID &lhs, const AgentID &rhs) { bool operator==(const AgentID &lhs, const AgentID &rhs) {
return lhs._id == rhs._id; return lhs._id == rhs._id;
} }
bool operator!=(const AgentID &lhs, const AgentID &rhs) { bool operator!=(const AgentID &lhs, const AgentID &rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
bool operator<(const AgentID &lhs, const AgentID &rhs) { bool operator<(const AgentID &lhs, const AgentID &rhs) {
return lhs._id < rhs._id; return lhs._id < rhs._id;
} }
std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs) { std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs) {
return lhs << rhs.to_string(); return lhs << rhs.to_string();
} }
AgentID Agent::get_agent_id() const { return this->_agent_id; } AgentID Agent::get_agent_id() const { return this->_agent_id; }
bool operator==(const Agent &lhs, const Agent &rhs) { bool operator==(const Agent &lhs, const Agent &rhs) {
return lhs._agent_id == rhs._agent_id; return lhs._agent_id == rhs._agent_id;
} }
bool operator!=(const Agent &lhs, const Agent &rhs) { return !(lhs == rhs); } bool operator!=(const Agent &lhs, const Agent &rhs) { return !(lhs == rhs); }
} // namespace kami } // namespace kami

View File

@@ -30,8 +30,8 @@
namespace kami { namespace kami {
std::ostream &operator<<(std::ostream &lhs, const Coord &rhs) { std::ostream &operator<<(std::ostream &lhs, const Coord &rhs) {
return lhs << rhs.to_string(); return lhs << rhs.to_string();
} }
} // namespace kami } // namespace kami

View File

@@ -25,135 +25,132 @@
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h> #include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid1d.h> #include <kami/grid1d.h>
#include <kami/kami.h>
#include <map> #include <map>
#include <utility>
#include <vector> #include <vector>
namespace kami { namespace kami {
int GridCoord1D::get_x_location() const { return _x_coord; } int GridCoord1D::get_x_location() const { return _x_coord; }
std::string GridCoord1D::to_string() const { std::string GridCoord1D::to_string() const {
return std::string("(" + std::to_string(_x_coord) + ")"); return std::string("(" + std::to_string(_x_coord) + ")");
} }
bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs) { bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs) {
return (lhs._x_coord == rhs._x_coord); return (lhs._x_coord == rhs._x_coord);
} }
bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs) { bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs) { std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs) {
return lhs << rhs.to_string(); return lhs << rhs.to_string();
} }
Grid1D::Grid1D(unsigned int maximum_x, bool wrap_x) { Grid1D::Grid1D(unsigned int maximum_x, bool wrap_x) {
_agent_grid = new std::vector<AgentID>[maximum_x]; _agent_grid = new std::vector<AgentID>[maximum_x];
_agent_index = new std::map<AgentID, GridCoord1D>; _agent_index = new std::map<AgentID, GridCoord1D>;
_maximum_x = maximum_x;
_wrap_x = wrap_x;
}
Grid1D::~Grid1D(void) { _maximum_x = maximum_x;
delete _agent_index; _wrap_x = wrap_x;
delete[] _agent_grid; }
}
bool Grid1D::delete_agent(AgentID agent_id) { Grid1D::~Grid1D() {
GridCoord1D coord = get_location_by_agent(agent_id); delete _agent_index;
delete[] _agent_grid;
}
return delete_agent(agent_id, coord); [[maybe_unused]] bool Grid1D::delete_agent(AgentID agent_id) {
} GridCoord1D coord = get_location_by_agent(agent_id);
bool Grid1D::is_location_valid(GridCoord1D coord) const { return delete_agent(agent_id, coord);
auto x = coord.get_x_location(); }
return (x >= 0 && x < static_cast<int>(_maximum_x));
}
bool Grid1D::is_location_empty(GridCoord1D coord) const { bool Grid1D::is_location_valid(const GridCoord1D& coord) const {
auto x = coord.get_x_location(); auto x = coord.get_x_location();
return (x >= 0 && x < static_cast<int>(_maximum_x));
}
return _agent_grid[x].size() == 0; bool Grid1D::is_location_empty(const GridCoord1D &coord) const {
} auto x = coord.get_x_location();
bool Grid1D::delete_agent(AgentID agent_id, GridCoord1D coord) { return _agent_grid[x].empty();
auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())]; }
for (auto test_agent_id = agent_list.begin(); bool Grid1D::delete_agent(AgentID agent_id, const GridCoord1D &coord) {
test_agent_id < agent_list.end(); test_agent_id++) { auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())];
if (*test_agent_id == agent_id) {
agent_list.erase(test_agent_id); for (auto test_agent_id = agent_list.begin();
_agent_index->erase(agent_id); test_agent_id < agent_list.end(); test_agent_id++) {
return true; if (*test_agent_id == agent_id) {
agent_list.erase(test_agent_id);
_agent_index->erase(agent_id);
return true;
}
} }
return false;
} }
return false; bool Grid1D::move_agent(AgentID agent_id, GridCoord1D coord) {
} GridCoord1D coord_current = get_location_by_agent(agent_id);
bool Grid1D::move_agent(AgentID agent_id, GridCoord1D coord) { if (delete_agent(agent_id, coord_current))
GridCoord1D coord_current = get_location_by_agent(agent_id); return add_agent(agent_id, std::move(coord));
return false;
if (delete_agent(agent_id, coord_current) == true)
return add_agent(agent_id, coord);
return false;
}
std::vector<GridCoord1D> Grid1D::get_neighborhood(AgentID agent_id,
bool include_center) const {
GridCoord1D coord = get_location_by_agent(agent_id);
return get_neighborhood(coord, include_center);
}
std::vector<GridCoord1D> Grid1D::get_neighborhood(GridCoord1D coord,
bool include_center) const {
std::vector<GridCoord1D> neighborhood;
auto x = coord.get_x_location();
// We assume our starting position is valid
if (include_center == true) neighborhood.push_back(coord);
// E, W
{
auto new_location = coord_wrap(GridCoord1D(x + 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord1D(x - 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
} }
return neighborhood; std::vector<GridCoord1D> Grid1D::get_neighborhood(AgentID agent_id, bool include_center) const {
} GridCoord1D coord = get_location_by_agent(agent_id);
std::vector<AgentID> *Grid1D::get_location_contents(GridCoord1D coord) const { return get_neighborhood(coord, include_center);
if (is_location_valid(coord)) return &_agent_grid[coord.get_x_location()]; }
return nullptr;
}
bool Grid1D::get_wrap_x(void) const { return _wrap_x; } std::vector<GridCoord1D> Grid1D::get_neighborhood(const GridCoord1D& coord, bool include_center) const {
std::vector<GridCoord1D> neighborhood;
auto x = coord.get_x_location();
unsigned int Grid1D::get_maximum_x(void) const { return _maximum_x; } // We assume our starting position is valid
if (include_center) neighborhood.push_back(coord);
GridCoord1D Grid1D::get_location_by_agent(AgentID agent_id) const { // E, W
return _agent_index->at(agent_id); {
} auto new_location = coord_wrap(GridCoord1D(x + 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord1D(x - 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
GridCoord1D Grid1D::coord_wrap(GridCoord1D coord) const { return neighborhood;
auto x = coord.get_x_location(); }
if (_wrap_x == true) std::vector<AgentID> *Grid1D::get_location_contents(const GridCoord1D& coord) const {
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x); if (is_location_valid(coord)) return &_agent_grid[coord.get_x_location()];
return GridCoord1D(x); return nullptr;
} }
[[maybe_unused]] bool Grid1D::get_wrap_x() const { return _wrap_x; }
[[maybe_unused]] unsigned int Grid1D::get_maximum_x() const { return _maximum_x; }
GridCoord1D Grid1D::get_location_by_agent(AgentID agent_id) const {
return _agent_index->at(agent_id);
}
GridCoord1D Grid1D::coord_wrap(const GridCoord1D& coord) const {
auto x = coord.get_x_location();
if(_wrap_x)
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
return GridCoord1D(x);
}
} // namespace kami } // namespace kami

View File

@@ -23,202 +23,198 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <map>
#include <utility>
#include <vector>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h> #include <kami/domain.h>
#include <kami/grid.h> #include <kami/grid.h>
#include <kami/grid2d.h> #include <kami/grid2d.h>
#include <kami/kami.h>
#include <map>
#include <vector>
namespace kami { namespace kami {
int GridCoord2D::get_x_location(void) const { int GridCoord2D::get_x_location() const {
return _x_coord; return _x_coord;
} }
int GridCoord2D::get_y_location(void) const { int GridCoord2D::get_y_location() const {
return _y_coord; return _y_coord;
} }
std::string GridCoord2D::to_string() const { std::string GridCoord2D::to_string() const {
return std::string("(" + std::to_string(_x_coord) + ", " + return std::string("(" + std::to_string(_x_coord) + ", " +
std::to_string(_y_coord) + ")"); std::to_string(_y_coord) + ")");
} }
bool operator==(const GridCoord2D &lhs, const GridCoord2D &rhs) { bool operator==(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return (lhs._x_coord == rhs._x_coord && lhs._y_coord == rhs._y_coord); return (lhs._x_coord == rhs._x_coord && lhs._y_coord == rhs._y_coord);
} }
bool operator!=(const GridCoord2D &lhs, const GridCoord2D &rhs) { bool operator!=(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
std::ostream &operator<<(std::ostream &lhs, const GridCoord2D &rhs) { std::ostream &operator<<(std::ostream &lhs, const GridCoord2D &rhs) {
return lhs << rhs.to_string(); return lhs << rhs.to_string();
} }
Grid2D::Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, Grid2D::Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
bool wrap_y) { bool wrap_y) {
_maximum_x = maximum_x; _maximum_x = maximum_x;
_maximum_y = maximum_y; _maximum_y = maximum_y;
_wrap_x = wrap_x; _wrap_x = wrap_x;
_wrap_y = wrap_y; _wrap_y = wrap_y;
_agent_grid = new std::vector<AgentID> *[_maximum_x]; _agent_grid = new std::vector<AgentID> *[_maximum_x];
for (auto i = 0; i < _maximum_x; i++) for (auto i = 0; i < _maximum_x; i++)
_agent_grid[i] = new std::vector<AgentID>[_maximum_y]; _agent_grid[i] = new std::vector<AgentID>[_maximum_y];
_agent_index = new std::map<AgentID, GridCoord2D>; _agent_index = new std::map<AgentID, GridCoord2D>;
} }
Grid2D::~Grid2D(void) { Grid2D::~Grid2D() {
delete _agent_index; delete _agent_index;
for (auto i = 0; i < _maximum_x; i++) delete[] _agent_grid[i]; for (auto i = 0; i < _maximum_x; i++) delete[] _agent_grid[i];
delete[] _agent_grid; delete[] _agent_grid;
} }
bool Grid2D::delete_agent(AgentID agent_id) { [[maybe_unused]] bool Grid2D::delete_agent(AgentID agent_id) {
auto location = get_location_by_agent(agent_id); auto coord = get_location_by_agent(agent_id);
return delete_agent(agent_id, location); return delete_agent(agent_id, coord);
} }
bool Grid2D::delete_agent(AgentID agent_id, GridCoord2D location) { bool Grid2D::delete_agent(AgentID agent_id, const GridCoord2D &coord) {
auto agent_list = _agent_grid[static_cast<int>(location.get_x_location())] auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())][static_cast<int>(coord.get_y_location())];
[static_cast<int>(location.get_y_location())];
for (auto test_agent_id = agent_list.begin(); for (auto test_agent_id = agent_list.begin();
test_agent_id < agent_list.end(); test_agent_id++) { test_agent_id < agent_list.end(); test_agent_id++) {
if (*test_agent_id == agent_id) { if (*test_agent_id == agent_id) {
agent_list.erase(test_agent_id); agent_list.erase(test_agent_id);
_agent_index->erase(agent_id); _agent_index->erase(agent_id);
return true; return true;
}
} }
return false;
} }
return false; bool Grid2D::is_location_valid(const GridCoord2D& coord) const {
} auto x = coord.get_x_location();
auto y = coord.get_y_location();
bool Grid2D::is_location_valid(GridCoord2D location) const { return (x >= 0 && x < static_cast<int>(_maximum_x) && y >= 0 &&
auto x = location.get_x_location(); y < static_cast<int>(_maximum_y));
auto y = location.get_y_location();
return (x >= 0 && x < static_cast<int>(_maximum_x) && y >= 0 &&
y < static_cast<int>(_maximum_y));
}
GridCoord2D Grid2D::get_location_by_agent(AgentID agent_id) const {
return _agent_index->at(agent_id);
}
bool Grid2D::move_agent(AgentID agent_id, GridCoord2D coord) {
GridCoord2D current_location = get_location_by_agent(agent_id);
if (delete_agent(agent_id, current_location) == true)
return add_agent(agent_id, coord);
return false;
}
bool Grid2D::get_wrap_x(void) const { return _wrap_x; }
bool Grid2D::get_wrap_y(void) const { return _wrap_y; }
std::vector<GridCoord2D> Grid2D::get_neighborhood(
AgentID agent_id, GridNeighborhoodType neighborhood_type,
bool includeCenter) const {
GridCoord2D location = get_location_by_agent(agent_id);
return get_neighborhood(location, neighborhood_type, includeCenter);
}
std::vector<GridCoord2D> Grid2D::get_neighborhood(
GridCoord2D location, GridNeighborhoodType neighborhood_type,
bool include_center) const {
std::vector<GridCoord2D> neighborhood;
auto x = location.get_x_location();
auto y = location.get_y_location();
// We assume our starting position is valid
if (include_center) neighborhood.push_back(location);
// N, E, S, W
{
auto new_location = coord_wrap(GridCoord2D(x, y - 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x, y + 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x + 1, y));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x - 1, y));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
} }
if (neighborhood_type == GridNeighborhoodType::Moore) { GridCoord2D Grid2D::get_location_by_agent(AgentID agent_id) const {
// NE, SE, SW, NW return _agent_index->at(agent_id);
}
bool Grid2D::move_agent(AgentID agent_id, GridCoord2D coord) {
GridCoord2D current_location = get_location_by_agent(agent_id);
if (delete_agent(agent_id, current_location))
return add_agent(agent_id, std::move(coord));
return false;
}
[[maybe_unused]] bool Grid2D::get_wrap_x() const { return _wrap_x; }
[[maybe_unused]] bool Grid2D::get_wrap_y() const { return _wrap_y; }
std::vector<GridCoord2D> Grid2D::get_neighborhood(
AgentID agent_id, GridNeighborhoodType neighborhood_type,
bool includeCenter) const {
GridCoord2D location = get_location_by_agent(agent_id);
return get_neighborhood(location, neighborhood_type, includeCenter);
}
std::vector<GridCoord2D> Grid2D::get_neighborhood(const GridCoord2D& location, GridNeighborhoodType neighborhood_type, bool include_center) const {
std::vector<GridCoord2D> neighborhood;
auto x = location.get_x_location();
auto y = location.get_y_location();
// We assume our starting position is valid
if (include_center) neighborhood.push_back(location);
// N, E, S, W
{ {
auto new_location = coord_wrap(GridCoord2D(x + 1, y - 1)); auto new_location = coord_wrap(GridCoord2D(x, y - 1));
if (is_location_valid(new_location)) if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location)); neighborhood.push_back(coord_wrap(new_location));
} }
{ {
auto new_location = coord_wrap(GridCoord2D(x + 1, y + 1)); auto new_location = coord_wrap(GridCoord2D(x, y + 1));
if (is_location_valid(new_location)) if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location)); neighborhood.push_back(coord_wrap(new_location));
} }
{ {
auto new_location = coord_wrap(GridCoord2D(x - 1, y + 1)); auto new_location = coord_wrap(GridCoord2D(x + 1, y));
if (is_location_valid(new_location)) if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location)); neighborhood.push_back(coord_wrap(new_location));
} }
{ {
auto new_location = coord_wrap(GridCoord2D(x - 1, y - 1)); auto new_location = coord_wrap(GridCoord2D(x - 1, y));
if (is_location_valid(new_location)) if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location)); neighborhood.push_back(coord_wrap(new_location));
} }
if (neighborhood_type == GridNeighborhoodType::Moore) {
// NE, SE, SW, NW
{
auto new_location = coord_wrap(GridCoord2D(x + 1, y - 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x + 1, y + 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x - 1, y + 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
{
auto new_location = coord_wrap(GridCoord2D(x - 1, y - 1));
if (is_location_valid(new_location))
neighborhood.push_back(coord_wrap(new_location));
}
}
return neighborhood;
} }
return neighborhood; std::vector<AgentID> *Grid2D::get_location_contents(const GridCoord2D& coord) const {
} if (is_location_valid(coord) && !is_location_empty(coord))
return &_agent_grid[coord.get_x_location()][coord.get_y_location()];
std::vector<AgentID> *Grid2D::get_location_contents( return nullptr;
GridCoord2D location) const {
if (is_location_valid(location) && !is_location_empty(location)) {
return &_agent_grid[location.get_x_location()]
[location.get_y_location()];
} }
return nullptr; [[maybe_unused]] unsigned int Grid2D::get_maximum_x() const { return _maximum_x; }
} [[maybe_unused]] unsigned int Grid2D::get_maximum_y() const { return _maximum_y; }
unsigned int Grid2D::get_maximum_x(void) const { return _maximum_x; } GridCoord2D Grid2D::coord_wrap(const GridCoord2D& coord) const {
unsigned int Grid2D::get_maximum_y(void) const { return _maximum_y; } auto x = coord.get_x_location();
auto y = coord.get_y_location();
GridCoord2D Grid2D::coord_wrap(GridCoord2D location) const { if (_wrap_x)
auto x = location.get_x_location(); x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
auto y = location.get_y_location(); if (_wrap_x)
y = (y + static_cast<int>(_maximum_y)) % static_cast<int>(_maximum_y);
return {x, y};
}
if (_wrap_x) bool Grid2D::is_location_empty(const GridCoord2D& coord) const {
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x); auto x = coord.get_x_location();
if (_wrap_x) auto y = coord.get_y_location();
y = (y + static_cast<int>(_maximum_y)) % static_cast<int>(_maximum_y);
return GridCoord2D(x, y);
}
bool Grid2D::is_location_empty(GridCoord2D location) const { return _agent_grid[x][y].empty();
auto x = location.get_x_location(); }
auto y = location.get_y_location();
return _agent_grid[x][y].size() == 0;
}
} // namespace kami } // namespace kami

View File

@@ -25,21 +25,19 @@
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h> #include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid1d.h> #include <kami/grid1d.h>
#include <kami/kami.h>
#include <kami/multigrid1d.h> #include <kami/multigrid1d.h>
namespace kami { namespace kami {
bool MultiGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) { bool MultiGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
if (is_location_valid(coord)) { if (is_location_valid(coord)) {
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord)); _agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
_agent_grid[coord.get_x_location()].push_back(agent_id); _agent_grid[coord.get_x_location()].push_back(agent_id);
return (true); return (true);
}
return (false);
} }
return (false);
}
} // namespace kami } // namespace kami

View File

@@ -25,26 +25,20 @@
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h> #include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid2d.h> #include <kami/grid2d.h>
#include <kami/kami.h>
#include <kami/multigrid2d.h> #include <kami/multigrid2d.h>
namespace kami { namespace kami {
MultiGrid2D::MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool MultiGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
bool wrap_x, bool wrap_y) if (is_location_valid(coord)) {
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {} _agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
agent_id);
return true;
}
bool MultiGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) { return false;
if (is_location_valid(coord)) {
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
agent_id);
return true;
} }
return false;
}
} // namespace kami } // namespace kami

View File

@@ -23,35 +23,29 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <kami/agent.h>
#include <kami/model.h>
#include <kami/random.h>
#include <kami/scheduler.h>
#include <chrono>
#include <iostream>
#include <random> #include <random>
#include <string> #include <string>
#include <utility>
#include <kami/model.h>
#include <kami/random.h>
namespace kami { namespace kami {
RandomScheduler::RandomScheduler(Model *model) : SequentialScheduler(model) {} RandomScheduler::RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng)
: SequentialScheduler(model) {
this->set_rng(std::move(rng));
}
RandomScheduler::RandomScheduler(Model *model, void RandomScheduler::step() {
std::shared_ptr<std::mt19937> rng) shuffle(_agent_list.begin(), _agent_list.end(), *_rng);
: SequentialScheduler(model) { this->SequentialScheduler::step();
this->set_rng(rng); }
}
void RandomScheduler::step() { void RandomScheduler::set_rng(std::shared_ptr<std::mt19937> rng) {
shuffle(_agent_list.begin(), _agent_list.end(), *_rng); this->_rng = std::move(rng);
this->SequentialScheduler::step(); }
}
void RandomScheduler::set_rng(std::shared_ptr<std::mt19937> rng) { [[maybe_unused]] std::shared_ptr<std::mt19937> RandomScheduler::get_rng() { return (_rng); }
this->_rng = rng;
}
std::shared_ptr<std::mt19937> RandomScheduler::get_rng() { return (_rng); }
} // namespace kami } // namespace kami

View File

@@ -23,42 +23,37 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <string>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/model.h> #include <kami/model.h>
#include <kami/scheduler.h>
#include <kami/sequential.h> #include <kami/sequential.h>
#include <random>
#include <string>
namespace kami { namespace kami {
SequentialScheduler::SequentialScheduler(Model *model) { SequentialScheduler::SequentialScheduler(Model *model) {
_step_counter = 0; _step_counter = 0;
_model = model; _model = model;
} }
void SequentialScheduler::add_agent(AgentID agent_id) { void SequentialScheduler::add_agent(AgentID agent_id) {
_agent_list.push_back(agent_id); _agent_list.push_back(agent_id);
} }
void SequentialScheduler::delete_agent(AgentID agent_id) { void SequentialScheduler::delete_agent(AgentID agent_id) {
for (auto agent_list_iter = _agent_list.begin(); for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++)
agent_list_iter < _agent_list.end(); agent_list_iter++) if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter); // ERROR HERE
return; }
// ERROR HERE void SequentialScheduler::step() {
} _step_counter++;
void SequentialScheduler::step() { for (auto agent_list_iter = _agent_list.begin();
_step_counter++; agent_list_iter < _agent_list.end(); agent_list_iter++) {
Agent *agent = _model->get_agent_by_id(*agent_list_iter);
for (auto agent_list_iter = _agent_list.begin(); if (agent != nullptr) agent->step();
agent_list_iter < _agent_list.end(); agent_list_iter++) { }
Agent *agent = _model->get_agent_by_id(*agent_list_iter);
if (agent != nullptr) agent->step();
} }
}
} // namespace kami } // namespace kami

View File

@@ -24,22 +24,18 @@
*/ */
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid1d.h>
#include <kami/kami.h>
#include <kami/sologrid1d.h> #include <kami/sologrid1d.h>
namespace kami { namespace kami {
bool SoloGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) { bool SoloGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
if (is_location_valid(coord) & is_location_empty(coord)) { if (is_location_valid(coord) & is_location_empty(coord)) {
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord)); _agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
_agent_grid[coord.get_x_location()].push_back(agent_id); _agent_grid[coord.get_x_location()].push_back(agent_id);
return true; return true;
}
return false;
} }
return false;
}
} // namespace kami } // namespace kami

View File

@@ -24,29 +24,20 @@
*/ */
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/domain.h>
#include <kami/grid.h>
#include <kami/grid2d.h>
#include <kami/kami.h>
#include <kami/sologrid2d.h> #include <kami/sologrid2d.h>
#include <vector> #include <vector>
namespace kami { namespace kami {
SoloGrid2D::SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool SoloGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
bool wrap_x, bool wrap_y) if (is_location_valid(coord) & is_location_empty(coord)) {
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {} _agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(agent_id);
return true;
}
bool SoloGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) { return false;
if (is_location_valid(coord) & is_location_empty(coord)) {
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
agent_id);
return true;
} }
return false;
}
} // namespace kami } // namespace kami

View File

@@ -23,55 +23,40 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <string>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/model.h> #include <kami/model.h>
#include <kami/scheduler.h>
#include <kami/sequential.h>
#include <kami/staged.h> #include <kami/staged.h>
#include <random>
#include <string>
namespace kami { namespace kami {
StagedScheduler::StagedScheduler(Model *model) { StagedScheduler::StagedScheduler(Model *model) {
_step_counter = 0; _step_counter = 0;
_model = model; _model = model;
}
StagedScheduler::~StagedScheduler() {}
void StagedScheduler::add_agent(AgentID agent_id) {
_agent_list.push_back(agent_id);
}
void StagedScheduler::delete_agent(AgentID agent_id) {
for (auto agent_list_iter = _agent_list.begin();
agent_list_iter < _agent_list.end(); agent_list_iter++)
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
return;
}
void StagedScheduler::step() {
_step_counter++;
for (auto agent_list_iter = _agent_list.begin();
agent_list_iter < _agent_list.end(); agent_list_iter++) {
StagedAgent *agent = dynamic_cast<StagedAgent *>(
_model->get_agent_by_id(*agent_list_iter));
if (agent != nullptr) agent->step();
// ERROR HERE
} }
for (auto agent_list_iter = _agent_list.begin(); void StagedScheduler::add_agent(AgentID agent_id) {
agent_list_iter < _agent_list.end(); agent_list_iter++) { _agent_list.push_back(agent_id);
StagedAgent *agent = dynamic_cast<StagedAgent *>(
_model->get_agent_by_id(*agent_list_iter));
if (agent != nullptr) agent->advance();
// ERROR HERE
} }
return; void StagedScheduler::delete_agent(AgentID agent_id) {
} for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++)
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
}
void StagedScheduler::step() {
_step_counter++;
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++) {
auto *agent = dynamic_cast<StagedAgent *>(_model->get_agent_by_id(*agent_list_iter));
if (agent != nullptr) agent->step();
}
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++) {
auto *agent = dynamic_cast<StagedAgent *>(_model->get_agent_by_id(*agent_list_iter));
if (agent != nullptr) agent->advance();
}
}
} // namespace kami } // namespace kami

View File

@@ -23,21 +23,23 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <string>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/config.h> #include <kami/config.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <CLI/App.hpp> #include <CLI/App.hpp>
#include <CLI/Config.hpp> #include <CLI/Config.hpp>
#include <CLI/Formatter.hpp> #include <CLI/Formatter.hpp>
#include <string>
using namespace kami; using namespace kami;
using namespace std; using namespace std;
class TestAgent : public Agent { class TestAgent : public Agent {
void step(){}; void step() override {};
}; };
int main(int argc, char **argv) { int main(int argc, char **argv) {
@@ -46,15 +48,12 @@ int main(int argc, char **argv) {
auto console = spdlog::stdout_color_st(ident); auto console = spdlog::stdout_color_st(ident);
string logLevelOption = "info"; string logLevelOption = "info";
app.add_option("-l", logLevelOption, "Set the logging level") app.add_option("-l", logLevelOption, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
CLI11_PARSE(app, argc, argv); CLI11_PARSE(app, argc, argv);
console->set_level(spdlog::level::from_str(logLevelOption)); console->set_level(spdlog::level::from_str(logLevelOption));
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, logLevelOption);
logLevelOption);
TestAgent test_agent; TestAgent test_agent;
console->debug("Successfully created Agent with ID {}", console->debug("Successfully created Agent with ID {}", test_agent.get_agent_id().to_string());
test_agent.get_agent_id().to_string());
} }

View File

@@ -23,15 +23,17 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <string>
#include <kami/agent.h> #include <kami/agent.h>
#include <kami/config.h> #include <kami/config.h>
#include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <CLI/App.hpp> #include <CLI/App.hpp>
#include <CLI/Config.hpp> #include <CLI/Config.hpp>
#include <CLI/Formatter.hpp> #include <CLI/Formatter.hpp>
#include <string>
using namespace kami; using namespace kami;
using namespace std; using namespace std;
@@ -42,15 +44,12 @@ int main(int argc, char **argv) {
auto console = spdlog::stdout_color_st(ident); auto console = spdlog::stdout_color_st(ident);
string logLevelOption = "info"; string logLevelOption = "info";
app.add_option("-l", logLevelOption, "Set the logging level") app.add_option("-l", logLevelOption, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
CLI11_PARSE(app, argc, argv); CLI11_PARSE(app, argc, argv);
console->set_level(spdlog::level::from_str(logLevelOption)); console->set_level(spdlog::level::from_str(logLevelOption));
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, logLevelOption);
logLevelOption);
AgentID testAgentID; AgentID testAgentID;
console->debug("Successfully created AgentID with ID {}", console->debug("Successfully created AgentID with ID {}", testAgentID.to_string());
testAgentID.to_string());
} }