19 Commits
0.5.1 ... 0.6.0

Author SHA1 Message Date
James P. Howard, II
d4db95f925 Merge branch 'release/0.6.0' 2022-08-19 20:57:58 -04:00
James P. Howard, II
0727030bcb Bump the version to 0.6.0 2022-08-19 20:57:47 -04:00
James P. Howard, II
85aede0721 We can be a little less circumspect in the testing 2022-08-19 20:56:12 -04:00
James P. Howard, II
06e98b1f94 Add build=missing to the Github workflow for Conan 2022-08-19 20:44:42 -04:00
James P. Howard, II
8613bc29b3 Added a to do list of things that should be done 2022-08-19 20:41:11 -04:00
James P. Howard, II
67cdf9bc29 Whitespace 2022-08-19 20:28:07 -04:00
James P. Howard, II
e7a5f342bf Updates to the Starter example reflecting Model changes 2022-08-19 20:27:50 -04:00
James P. Howard, II
9333e1c2fa Schedulers tests 2022-08-19 20:27:04 -04:00
James P. Howard, II
f18e2c99da Simplify the interface to random. I really have no idea why I let you set the RNG later, anyway. 2022-08-19 20:26:29 -04:00
James P. Howard, II
d884e603cb You know, there is no reason Model has to define the step/run interface
The user can do that for themselves
2022-08-19 19:21:43 -04:00
James P. Howard, II
78aca204f4 add using namespace kami to unit tests 2022-08-19 15:45:27 -04:00
James P. Howard, II
50b147beca Draft Population unit tests 2022-08-18 22:00:37 -04:00
James P. Howard, II
3dff3afb6e Automatically use all .cc files as tests 2022-08-18 18:17:47 -04:00
James P. Howard, II
80f98bdde0 Correction to examples readme 2022-08-18 16:57:27 -04:00
James P. Howard, II
72f0074d81 Completed first generation of unit tests on the grids 2022-08-18 16:56:16 -04:00
James P. Howard, II
f6967d0ec3 Versions of all supporting packages made current 2022-08-16 20:49:54 -04:00
James P. Howard, II
318f6dfecf Move dependencies for the examples to the examples' cmakelists 2022-08-16 11:34:53 -04:00
James P. Howard, II
05995525f1 Simplify overview in documentation 2022-08-12 13:40:56 -04:00
James P. Howard, II
d1ba71b416 Merge branch 'release/0.5.1' into develop 2022-08-11 22:21:23 -04:00
41 changed files with 3442 additions and 292 deletions

View File

@@ -34,7 +34,7 @@ jobs:
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Conan Install Dependencies
run: conan install -if build .
run: conan install -if build . --build=missing
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.

View File

@@ -34,7 +34,7 @@ jobs:
conan profile update settings.compiler.libcxx=libstdc++11 default
- name: Conan Install Dependencies
run: conan install -if build .
run: conan install -if build . --build=missing
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.

View File

@@ -5,8 +5,8 @@ cmake_minimum_required(VERSION 3.13)
set(PROJECT_NAME "kami")
set(VERSION_MAJOR 0)
set(VERSION_MINOR 5)
set(VERSION_PATCH 1)
set(VERSION_MINOR 6)
set(VERSION_PATCH 0)
set(VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
project(${PROJECT_NAME}
@@ -23,9 +23,6 @@ conan_basic_setup()
set(PROJECT_NAMESPACE ${PROJECT_NAME})
find_package(spdlog)
find_package(Threads)
if(CMAKE_COMPILER_IS_GNUCC)
option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" FALSE)
endif()

View File

@@ -3,7 +3,7 @@ from conans import ConanFile, CMake
class KamiConan(ConanFile):
name = "kami"
version = "0.5.1"
version = "0.6.0"
license = "MIT"
author = "James P. Howard, II <james.howard@jhu.edu>"
url = "https://github.com/jhuapl/kami"
@@ -44,8 +44,8 @@ class KamiConan(ConanFile):
def requirements(self):
self.requires("fmt/7.1.3")
self.requires("spdlog/1.8.5")
self.requires("cli11/1.9.1")
self.requires("fmt/9.0.0")
self.requires("spdlog/1.10.0")
self.requires("cli11/2.2.0")
self.requires("neargye-semver/0.3.0")
self.requires("gtest/cci.20210126")

View File

@@ -1,6 +1,13 @@
Changelog
=========
- :release:`0.6.0 <2022.08.19>`
- :feature:`0` Added a to do list to the documentation
- :feature:`0` Completed basic unit tests
- :feature:`0` Removed step()/run() from Model interface
- :feature:`0` Revised interfaces to the grids
- :feature:`0` Updated all support packages to most current versions
- :release:`0.5.1 <2022.08.11>`
- :support:`0` Completed initial unit tests
- :support:`0` Added background info to READ ME

View File

@@ -18,13 +18,49 @@ Introduction
Kami is Agent-Based Modeling in Modern C++.
Overview
========
Agent-based models (ABMs) are models for simulating the actions of
individual actors within a provided environment to understand the
behavior of the agents, most individually and collectively. ABMs
are particularly suited for addressing problems governed by nonlinear
processes or where there is a wide variety of potential responses
an individual agent may provide depending on the environment and
behavior of other agents. Because of this, ABMs have become powerful
tools in both simulation and modeling, especially in public health
and ecology, where they are also known as individual-based models.
ABMs also provide support in economic, business, robotics, and many
other fields.
Design Objectives
-----------------
Kami provides agent-based modeling modern C++. The objectives in
writing Kami are that it be lightweight, memory-efficient, and fast.
It should be possible to develop a simple working model in under
one hour of C++ development time. Accordingly, the platform is
modeled on the Mesa_ library in Python, which itself was inspired
by the MASON_ library in Java.
Many ABM platforms are designed around interaction and real time
observation of the agent dynamics. Kami does not provide a
visualization interface. Instead, Kami is meant to be used for
ABMs requiring many runs with different starting conditions.
Accordingly, Kami is single-threaded and multiple cores should be
taken advantage of through multiple parallel runs of the supervising
model.
.. _MASON: https://cs.gmu.edu/~eclab/projects/mason/
.. _Mesa: https://mesa.readthedocs.io
.. toctree::
:hidden:
:maxdepth: 2
overview
installation
tutorial
api/library_root
changelog
todo
license

View File

@@ -1,37 +0,0 @@
Overview
========
Agent-based models (ABMs) are models for simulating the actions of
individual actors within a provided environment to understand the
behavior of the agents, most individually and collectively. ABMs
are particularly suited for addressing problems governed by nonlinear
processes or where there is a wide variety of potential responses
an individual agent may provide depending on the environment and
behavior of other agents. Because of this, ABMs have become powerful
tools in both simulation and modeling, especially in public health
and ecology, where they are also known as individual-based models.
ABMs also provide support in economic, business, robotics, and many
other fields.
Design Objectives
-----------------
Kami provides agent-based modeling modern C++. The objectives in
writing Kami are that it be lightweight, memory-efficient, and fast.
It should be possible to develop a simple working model in under
one hour of C++ development time. Accordingly, the platform is
modeled on the Mesa_ library in Python, which itself was inspired
by the MASON_ library in Java.
Many ABM platforms are designed around interaction and real time
observation of the agent dynamics. Kami does not provide a
visualization interface. Instead, Kami is meant to be used for
ABMs requiring many runs with different starting conditions.
Accordingly, Kami is single-threaded and multiple cores should be
taken advantage of through multiple parallel runs of the supervising
model.
.. _MASON: https://cs.gmu.edu/~eclab/projects/mason/
.. _Mesa: https://mesa.readthedocs.io
.. toctree::

24
docs/todo.rst Normal file
View File

@@ -0,0 +1,24 @@
To Do List
==========
Must Dos
--------
The list below is a list of things considered necessary before
a 1.0 release. This list is *not* static.
- Network domain
- Data collection process
- Demonstration of data collection process
- Tutorial write up
Wishlist
--------
The list below is a list of things considered nice to have at
any point.
- Revise unit tests to take advantage of fixtures
- Documentation with basic introduction to ABMs
- Network Boltzmann model example
- Additional examples as appropriate
.. toctree::

View File

@@ -3,5 +3,5 @@
Each folder in here is automatically traversed by the root level cmake list file.
1. Copy one of the existing folders to a new name.
2. The name of the folder will be the name of the library
2. The name of the folder will be the name of the example
3. Change the source file list.

View File

@@ -2,6 +2,8 @@
# Set minimum version of CMake.
cmake_minimum_required(VERSION 3.13)
find_package(spdlog)
set(EXAMPLE_NAME "boltzmann1d")
project(${EXAMPLE_NAME} LANGUAGES CXX)

View File

@@ -26,15 +26,14 @@
#include "boltzmann1d.h"
#include <exception>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <random>
#include <stdexcept>
#include <CLI/App.hpp>
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/CLI.hpp>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
@@ -78,7 +77,7 @@ kami::AgentID MoneyAgent1D::step(std::shared_ptr<kami::Model> model) {
return this->get_agent_id();
}
kami::GridCoord1D MoneyAgent1D::move_agent(std::shared_ptr<kami::Model> model) {
std::optional<kami::GridCoord1D> MoneyAgent1D::move_agent(std::shared_ptr<kami::Model> model) {
console->trace("Entering move_agent");
auto agent_id = get_agent_id();
@@ -87,9 +86,12 @@ kami::GridCoord1D MoneyAgent1D::move_agent(std::shared_ptr<kami::Model> model) {
throw (std::domain_error("model is missing domain"));
auto world = std::static_pointer_cast<kami::MultiGrid1D>(domain.value());
auto move_list = world->get_neighborhood(agent_id, false);
auto move_list_opt = world->get_neighborhood(agent_id, false);
if (!move_list_opt)
return std::nullopt;
auto move_list = move_list_opt.value();
std::uniform_int_distribution<int> dist(0, (int) move_list->size() - 1);
auto new_location = move_list->at(dist(*rng));
auto new_location = *std::next(move_list->begin(), dist(*rng));
console->trace("Moving Agent {} to location {}", agent_id, new_location);
world->move_agent(agent_id, new_location);
@@ -113,13 +115,17 @@ std::optional<kami::AgentID> MoneyAgent1D::give_money(std::shared_ptr<kami::Mode
auto population = std::static_pointer_cast<kami::Population>(agents.value());
auto location = world->get_location_by_agent(agent_id);
auto cell_mates = world->get_location_contents(location.value());
auto cell_mates_opt = world->get_location_contents(location.value());
if (!cell_mates_opt)
return std::nullopt;
auto cell_mates = cell_mates_opt.value();
if (cell_mates->size() < 2)
return std::nullopt;
std::uniform_int_distribution<int> dist(0, (int) cell_mates->size() - 1);
kami::AgentID other_agent_id = cell_mates->at(dist(*rng));
auto other_agent_id = *std::next(cell_mates->begin(), dist(*rng));
auto other_agent = std::static_pointer_cast<MoneyAgent1D>(population->get_agent_by_id(other_agent_id).value());
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
@@ -157,12 +163,6 @@ BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents, unsig
}
}
std::shared_ptr<kami::Model> BoltzmannWealthModel1D::run(unsigned int steps) {
for (auto i = 0; i < steps; i++)
step();
return shared_from_this();
}
std::shared_ptr<kami::Model> BoltzmannWealthModel1D::step() {
console->trace("Executing model step {}", ++_step_count);
_sched->step(shared_from_this());
@@ -175,8 +175,14 @@ int main(int argc, char **argv) {
CLI::App app{ident};
unsigned int x_size = 16, agent_count = x_size, max_steps = 100, initial_seed = 42;
// This exercise is really stupid.
auto levels_list = std::make_unique<std::list<std::string>>();
for (auto &level_name: SPDLOG_LEVEL_NAMES)
levels_list->push_back(std::string(level_name.data(), level_name.size()));
app.add_option("-c", agent_count, "Set the number of agents")->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")->check(
CLI::IsMember(levels_list.get(), CLI::ignore_case));
app.add_option("-n", max_steps, "Set the number of steps to run the model")->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 columns")->check(CLI::PositiveNumber);

View File

@@ -65,7 +65,7 @@ public:
/**
* Move the agent to a random location on the world
*/
kami::GridCoord1D move_agent(std::shared_ptr<kami::Model> model);
std::optional<kami::GridCoord1D> move_agent(std::shared_ptr<kami::Model> model);
/**
* Give money to a random agent
@@ -96,14 +96,7 @@ public:
/**
* Execute a single time-step for the model.
*/
std::shared_ptr<kami::Model> step() override;
/**
* Execute a number of time-steps for the model.
*
* @param[in] n the number of steps to execute.
*/
std::shared_ptr<kami::Model> run(unsigned int n) override;
std::shared_ptr<kami::Model> step();
private:
unsigned int _step_count;

View File

@@ -2,6 +2,8 @@
# Set minimum version of CMake.
cmake_minimum_required(VERSION 3.13)
find_package(spdlog)
set(EXAMPLE_NAME "boltzmann2d")
project(${EXAMPLE_NAME} LANGUAGES CXX)

View File

@@ -26,15 +26,14 @@
#include "boltzmann2d.h"
#include <exception>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <random>
#include <stdexcept>
#include <CLI/App.hpp>
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/CLI.hpp>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
@@ -78,7 +77,7 @@ kami::AgentID MoneyAgent2D::step(std::shared_ptr<kami::Model> model) {
return this->get_agent_id();
}
kami::GridCoord2D MoneyAgent2D::move_agent(std::shared_ptr<kami::Model> model) {
std::optional<kami::GridCoord2D> MoneyAgent2D::move_agent(std::shared_ptr<kami::Model> model) {
console->trace("Entering move_agent");
auto agent_id = get_agent_id();
@@ -87,9 +86,12 @@ kami::GridCoord2D MoneyAgent2D::move_agent(std::shared_ptr<kami::Model> model) {
throw (std::domain_error("model is missing domain"));
auto world = std::static_pointer_cast<kami::MultiGrid2D>(domain.value());
auto move_list = world->get_neighborhood(agent_id, false, kami::GridNeighborhoodType::Moore);
auto move_list_opt = world->get_neighborhood(agent_id, false, kami::GridNeighborhoodType::VonNeumann);
if (!move_list_opt)
return std::nullopt;
auto move_list = move_list_opt.value();
std::uniform_int_distribution<int> dist(0, (int) move_list->size() - 1);
auto new_location = move_list->at(dist(*rng));
auto new_location = *std::next(move_list->begin(), dist(*rng));
console->trace("Moving Agent {} to location {}", agent_id, new_location);
world->move_agent(agent_id, new_location);
@@ -113,13 +115,17 @@ std::optional<kami::AgentID> MoneyAgent2D::give_money(std::shared_ptr<kami::Mode
auto population = std::static_pointer_cast<kami::Population>(agents.value());
auto location = world->get_location_by_agent(agent_id);
auto cell_mates = world->get_location_contents(location.value());
auto cell_mates_opt = world->get_location_contents(location.value());
if (!cell_mates_opt)
return std::nullopt;
auto cell_mates = cell_mates_opt.value();
if (cell_mates->size() < 2)
return std::nullopt;
std::uniform_int_distribution<int> dist(0, (int) cell_mates->size() - 1);
kami::AgentID other_agent_id = cell_mates->at(dist(*rng));
auto other_agent_id = *std::next(cell_mates->begin(), dist(*rng));
auto other_agent = std::static_pointer_cast<MoneyAgent2D>(population->get_agent_by_id(other_agent_id).value());
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
@@ -158,12 +164,6 @@ BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents, unsig
}
}
std::shared_ptr<kami::Model> BoltzmannWealthModel2D::run(unsigned int steps) {
for (auto i = 0; i < steps; i++)
step();
return shared_from_this();
}
std::shared_ptr<kami::Model> BoltzmannWealthModel2D::step() {
console->trace("Executing model step {}", _step_count++);
_sched->step(shared_from_this());
@@ -176,8 +176,14 @@ int main(int argc, char **argv) {
CLI::App app{ident};
unsigned int x_size = 16, y_size = 16, agent_count = x_size * y_size, max_steps = 100, initial_seed = 42;
// This exercise is really stupid.
auto levels_list = std::make_unique<std::list<std::string>>();
for (auto &level_name: SPDLOG_LEVEL_NAMES)
levels_list->push_back(std::string(level_name.data(), level_name.size()));
app.add_option("-c", agent_count, "Set the number of agents")->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")->check(
CLI::IsMember(levels_list.get(), CLI::ignore_case));
app.add_option("-n", max_steps, "Set the number of steps to run the model")->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 columns")->check(CLI::PositiveNumber);

View File

@@ -64,7 +64,7 @@ public:
/**
* Move the agent to a random location on the world
*/
kami::GridCoord2D move_agent(std::shared_ptr<kami::Model> model);
std::optional<kami::GridCoord2D> move_agent(std::shared_ptr<kami::Model> model);
/**
* Give money to a random agent
@@ -99,14 +99,7 @@ public:
/**
* Execute a single time-step for the model.
*/
std::shared_ptr<kami::Model> step() override;
/**
* Execute a number of time-steps for the model.
*
* @param[in] n the number of steps to execute.
*/
std::shared_ptr<kami::Model> run(unsigned int n) override;
std::shared_ptr<kami::Model> step();
private:
unsigned int _step_count;

View File

@@ -2,6 +2,8 @@
# Set minimum version of CMake.
cmake_minimum_required(VERSION 3.13)
find_package(spdlog)
set(EXAMPLE_NAME "starter")
project(${EXAMPLE_NAME} LANGUAGES CXX)

View File

@@ -25,13 +25,12 @@
#include "starter.h"
#include <list>
#include <map>
#include <memory>
#include <random>
#include <CLI/App.hpp>
#include <CLI/Config.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/CLI.hpp>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>
@@ -80,7 +79,7 @@ StarterModel::StarterModel(unsigned int number_agents, unsigned int new_seed) {
_step_count = 0;
for (unsigned int i = 0; i < number_agents; i++) {
for (auto i = 0; i < number_agents; i++) {
auto new_agent = std::make_shared<StarterAgent>();
console->trace("Initializing agent with AgentID {}", new_agent->get_agent_id());
@@ -88,11 +87,6 @@ StarterModel::StarterModel(unsigned int number_agents, unsigned int new_seed) {
}
}
std::shared_ptr<kami::Model> StarterModel::run(unsigned int steps) {
for (auto i = 0; i < steps; i++) step();
return shared_from_this();
}
std::shared_ptr<kami::Model> StarterModel::step() {
console->trace("Executing model step {}", ++_step_count);
_sched->step(shared_from_this());
@@ -105,8 +99,14 @@ int main(int argc, char **argv) {
CLI::App app{ident};
unsigned int agent_count = 100, max_steps = 100, initial_seed = 8675309;
// This exercise is really stupid.
auto levels_list = std::make_unique<std::list<std::string>>();
for (auto &level_name: SPDLOG_LEVEL_NAMES)
levels_list->push_back(std::string(level_name.data(), level_name.size()));
app.add_option("-c", agent_count, "Set the number of agents")->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")->check(
CLI::IsMember(levels_list.get(), CLI::ignore_case));
app.add_option("-n", max_steps, "Set the number of steps to run the model")->check(CLI::PositiveNumber);
app.add_option("-s", initial_seed, "Set the initial seed")->check(CLI::Number);
CLI11_PARSE(app, argc, argv);

View File

@@ -82,14 +82,7 @@ public:
/**
* Execute a single time-step for the model.
*/
std::shared_ptr<kami::Model> step() override;
/**
* Execute a number of time-steps for the model.
*
* @param[in] n the number of steps to execute.
*/
std::shared_ptr<kami::Model> run(unsigned int n) override;
std::shared_ptr<kami::Model> step();
};
#endif // STARTER_H

View File

@@ -32,8 +32,9 @@
#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
#include <unordered_set>
#include <kami/domain.h>
#include <kami/grid.h>
@@ -171,12 +172,13 @@ namespace kami {
*
* @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 `set` of `AgentID`s. The pointer is to the
* 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
* should not be deleted when no longer used.
*/
[[nodiscard]] std::unique_ptr<std::vector<AgentID>> get_location_contents(const GridCoord1D &coord) const;
[[nodiscard]] std::optional<std::shared_ptr<std::set<AgentID>>>
get_location_contents(const GridCoord1D &coord) const;
/**
* @brief Inquire to whether the grid wraps in the `x` dimension.
@@ -192,10 +194,10 @@ namespace kami {
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a vector of `GridCoord1D` that includes all of the coordinates
* @return an `unordered_set` of `GridCoord1D` that includes all of the coordinates
* for all adjacent points.
*/
[[nodiscard]] std::unique_ptr<std::vector<GridCoord1D>>
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<GridCoord1D>>>
get_neighborhood(const AgentID agent_id, const bool include_center) const;
/**
@@ -205,10 +207,10 @@ namespace kami {
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a vector of `GridCoord1D` that includes all of the coordinates
* @return an `unordered_set` of `GridCoord1D` that includes all of the coordinates
* for all adjacent points.
*/
[[nodiscard]] std::unique_ptr<std::vector<GridCoord1D>>
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<GridCoord1D>>>
get_neighborhood(const GridCoord1D &coord, const bool include_center) const;
/**
@@ -220,7 +222,7 @@ namespace kami {
protected:
/**
* @brief A vector containing the `AgentID`s of all agents assigned to this
* @brief An `unordered_set` containing the `AgentID`s of all agents assigned to this
* grid.
*/
std::unique_ptr<std::unordered_multimap<GridCoord1D, AgentID>> _agent_grid;

View File

@@ -31,9 +31,10 @@
#include <iostream>
#include <map>
#include <optional>
#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
#include <unordered_set>
#include <kami/domain.h>
#include <kami/grid.h>
@@ -181,12 +182,13 @@ namespace kami {
*
* @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 `set` of `AgentID`s. The pointer is to the
* 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
* should not be deleted when no longer used.
*/
[[nodiscard]] std::unique_ptr<std::vector<AgentID>> get_location_contents(const GridCoord2D &coord) const;
[[nodiscard]] std::optional<std::shared_ptr<std::set<AgentID>>>
get_location_contents(const GridCoord2D &coord) const;
/**
* @brief Inquire to whether the grid wraps in the `x` dimension.
@@ -210,12 +212,12 @@ namespace kami {
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a vector of `GridCoord1D` that includes all of the coordinates
* @return a set of `GridCoord1D` that includes all of the coordinates
* for all adjacent points.
*
* @see `NeighborhoodType`
*/
[[nodiscard]] std::unique_ptr<std::vector<GridCoord2D>>
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<GridCoord2D>>>
get_neighborhood(AgentID agent_id, bool include_center, GridNeighborhoodType neighborhood_type) const;
/**
@@ -226,12 +228,12 @@ namespace kami {
* @param[in] include_center should the center-point, occupied by the agent,
* be in the list.
*
* @return a vector of `GridCoord1D` that includes all of the coordinates
* @return a set of `GridCoord2D` that includes all of the coordinates
* for all adjacent points.
*
* @see `NeighborhoodType`
*/
[[nodiscard]] std::unique_ptr<std::vector<GridCoord2D>>
[[nodiscard]] std::optional<std::shared_ptr<std::unordered_set<GridCoord2D>>>
get_neighborhood(const GridCoord2D &coord, bool include_center, GridNeighborhoodType neighborhood_type) const;
/**
@@ -250,7 +252,7 @@ namespace kami {
protected:
/**
* @brief A vector containing the `AgentID`s of all agents assigned to this
* @brief A map containing the `AgentID`s of all agents assigned to this
* grid.
*/
std::unique_ptr<std::unordered_multimap<GridCoord2D, AgentID>> _agent_grid;

View File

@@ -45,27 +45,6 @@ namespace kami {
class LIBKAMI_EXPORT Model : public std::enable_shared_from_this<Model> {
public:
/**
* @brief Execute a fixed number of time-steps for the model.
*
* @details This function should execute a fixed number of time-steps for the model.
*
* @param[in] n the number of time steps to execute.
*
* @returns a shared pointer to this instance of `Model`
*/
virtual std::shared_ptr<Model> run(unsigned int n) = 0;
/**
* @brief Execute a single time-step for the model.
*
* @details 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.
*
* @returns a shared pointer to this instance of `Model`
*/
virtual std::shared_ptr<Model> step() = 0;
/**
* @brief Get the `Domain` associated with this model
*

View File

@@ -88,9 +88,9 @@ namespace kami {
* @param rng [in] A uniform random number generator of type `std::mt19937`,
* used as the source of randomness.
*
* @returns a shared pointer to this instance of `RandomScheduler`
* @returns a shared pointer to the random number generator
*/
std::shared_ptr<RandomScheduler> set_rng(std::shared_ptr<std::ranlux24> rng);
std::shared_ptr<std::ranlux24> set_rng(std::shared_ptr<std::ranlux24> rng);
/**
* @brief Get the RNG

View File

@@ -62,7 +62,7 @@ namespace kami {
*
* @returns returns vector of agents successfully stepped
*/
std::optional<std::shared_ptr<std::vector<AgentID>>> step(std::shared_ptr<Model> model) override;
std::optional<std::shared_ptr<std::vector<AgentID>>> step(std::shared_ptr<Model> model) override;
/**
* @brief Execute a single time step.

View File

@@ -30,9 +30,10 @@
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
namespace kami {
@@ -109,51 +110,54 @@ namespace kami {
return add_agent(agent_id, coord);
}
std::unique_ptr<std::vector<GridCoord1D>>
std::optional<std::shared_ptr<std::unordered_set<GridCoord1D>>>
Grid1D::get_neighborhood(const AgentID agent_id, const bool include_center) const {
auto coord = get_location_by_agent(agent_id);
if (!coord)
return std::nullopt;
return std::move(get_neighborhood(coord.value(), include_center));
}
std::unique_ptr<std::vector<GridCoord1D>>
std::optional<std::shared_ptr<std::unordered_set<GridCoord1D>>>
Grid1D::get_neighborhood(const GridCoord1D &coord, const bool include_center) const {
auto neighborhood = std::make_unique<std::vector<GridCoord1D>>();
auto neighborhood = std::make_shared<std::unordered_set<GridCoord1D>>();
auto x = coord.get_x_location();
// We assume our starting position is valid
if (include_center)
neighborhood->push_back(coord);
neighborhood->insert(coord);
// E, W
{
auto new_location = coord_wrap(GridCoord1D(x + 1));
if (is_location_valid(new_location))
neighborhood->push_back(coord_wrap(new_location));
neighborhood->insert(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));
neighborhood->insert(coord_wrap(new_location));
}
return std::move(neighborhood);
}
std::unique_ptr<std::vector<AgentID>> Grid1D::get_location_contents(const GridCoord1D &coord) const {
auto agent_ids = std::make_unique<std::vector<AgentID>>();
std::optional<std::shared_ptr<std::set<AgentID>>> Grid1D::get_location_contents(const GridCoord1D &coord) const {
auto agent_ids = std::make_shared<std::set<AgentID>>();
if (!is_location_valid(coord))
return std::move(agent_ids);
return std::nullopt;
if (is_location_empty(coord))
return std::move(agent_ids);
return agent_ids;
auto agent_range = _agent_grid->equal_range(coord);
if (agent_range.first == agent_range.second)
return std::move(agent_ids);
return agent_ids;
for (auto i = agent_range.first; i != agent_range.second; i++)
agent_ids->push_back(i->second);
return std::move(agent_ids);
agent_ids->insert(i->second);
return agent_ids;
}
bool Grid1D::get_wrap_x() const { return _wrap_x; }

View File

@@ -118,45 +118,47 @@ namespace kami {
return add_agent(agent_id, coord);
}
std::unique_ptr<std::vector<GridCoord2D>>
std::optional<std::shared_ptr<std::unordered_set<GridCoord2D>>>
Grid2D::get_neighborhood(const AgentID agent_id, const bool include_center,
const GridNeighborhoodType neighborhood_type) const {
auto coord = get_location_by_agent(agent_id);
if (!coord)
return std::nullopt;
return std::move(get_neighborhood(coord.value(), include_center, neighborhood_type));
}
std::unique_ptr<std::vector<GridCoord2D>>
std::optional<std::shared_ptr<std::unordered_set<GridCoord2D>>>
Grid2D::get_neighborhood(const GridCoord2D &coord, const bool include_center,
const GridNeighborhoodType neighborhood_type) const {
auto neighborhood = std::make_unique<std::vector<GridCoord2D>>();
auto neighborhood = std::make_unique<std::unordered_set<GridCoord2D>>();
auto x = coord.get_x_location();
auto y = coord.get_y_location();
// We assume our starting position is valid
if (include_center)
neighborhood->push_back(coord);
neighborhood->insert(coord);
// 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));
neighborhood->insert(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));
neighborhood->insert(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));
neighborhood->insert(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));
neighborhood->insert(coord_wrap(new_location));
}
if (neighborhood_type == GridNeighborhoodType::Moore) {
@@ -164,42 +166,43 @@ namespace kami {
{
auto new_location = coord_wrap(GridCoord2D(x + 1, y - 1));
if (is_location_valid(new_location))
neighborhood->push_back(coord_wrap(new_location));
neighborhood->insert(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));
neighborhood->insert(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));
neighborhood->insert(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));
neighborhood->insert(coord_wrap(new_location));
}
}
return std::move(neighborhood);
}
std::unique_ptr<std::vector<AgentID>> Grid2D::get_location_contents(const GridCoord2D &coord) const {
auto agent_ids = std::make_unique<std::vector<AgentID>>();
std::optional<std::shared_ptr<std::set<AgentID>>> Grid2D::get_location_contents(const GridCoord2D &coord) const {
auto agent_ids = std::make_shared<std::set<AgentID>>();
if (!is_location_valid(coord))
return std::move(agent_ids);
return std::nullopt;
if (is_location_empty(coord))
return std::move(agent_ids);
return agent_ids;
auto agent_range = _agent_grid->equal_range(coord);
if (agent_range.first == agent_range.second)
return std::move(agent_ids);
return agent_ids;
for (auto i = agent_range.first; i != agent_range.second; i++)
agent_ids->push_back(i->second);
return std::move(agent_ids);
agent_ids->insert(i->second);
return agent_ids;
}
bool Grid2D::get_wrap_x() const { return _wrap_x; }

View File

@@ -27,6 +27,7 @@
#include <memory>
#include <optional>
#include <random>
#include <utility>
#include <vector>
#include <kami/model.h>
@@ -40,13 +41,16 @@ namespace kami {
}
std::optional<std::shared_ptr<std::vector<AgentID>>> RandomScheduler::step(std::shared_ptr<Model> model, std::shared_ptr<std::vector<AgentID>> agent_list) {
shuffle(agent_list->begin(),agent_list->end(), *_rng);
if (_rng == nullptr)
return std::nullopt;
shuffle(agent_list->begin(), agent_list->end(), *_rng);
return std::move(this->SequentialScheduler::step(model, agent_list));
}
std::shared_ptr<RandomScheduler> RandomScheduler::set_rng(std::shared_ptr<std::ranlux24> rng) {
std::shared_ptr<std::ranlux24> RandomScheduler::set_rng(std::shared_ptr<std::ranlux24> rng) {
this->_rng = std::move(rng);
return shared_from_this();
return _rng;
}
std::shared_ptr<std::ranlux24> RandomScheduler::get_rng() { return (this->_rng); }

View File

@@ -5,42 +5,14 @@
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
create_test(
NAME unit-kami-agent
SOURCES unit-kami-agent.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND unit-kami-agent
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
create_test(
NAME unit-kami-agentid
SOURCES unit-kami-agentid.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND unit-kami-agentid
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
create_test(
NAME unit-kami-model
SOURCES unit-kami-model.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND unit-kami-model
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
create_test(
NAME unit-kami-multigrid1d
SOURCES unit-kami-multigrid1d.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND unit-kami-multigrid1d
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
create_test(
NAME unit-kami-stagedagent
SOURCES unit-kami-stagedagent.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND unit-kami-stagedagent
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
file(GLOB test_modules "${CMAKE_CURRENT_SOURCE_DIR}/*.cc")
FOREACH (test_module ${test_modules})
cmake_path(GET test_module STEM test_src)
create_test(
NAME ${test_src}
SOURCES ${test_src}.cc
PUBLIC_LINKED_TARGETS gmock gtest kami::libkami Threads::Threads
COMMAND ${test_src}
PUBLIC_COMPILE_FEATURES ${COVERAGE_FLAGS}
)
ENDFOREACH ()

View File

@@ -30,22 +30,17 @@
#include <gtest/gtest.h>
class TestAgent : public kami::Agent {
using namespace kami;
using namespace std;
class TestAgent : public Agent {
public:
kami::AgentID step(std::shared_ptr<kami::Model> model) override {
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public kami::Model {
public:
std::shared_ptr<kami::Model> step() override {
return shared_from_this();
}
std::shared_ptr<kami::Model> run(unsigned int) override {
return shared_from_this();
}
class TestModel : public Model {
};
TEST(Agent, DefaultConstructor) {
@@ -67,7 +62,7 @@ TEST(Agent, get_agent_id) {
TEST(Agent, step) {
TestAgent agent_foo;
TestAgent agent_bar;
auto model_world = std::make_shared<TestModel>();
auto model_world = make_shared<TestModel>();
EXPECT_EQ(agent_foo.get_agent_id(), agent_foo.step(model_world));
EXPECT_NE(agent_bar.get_agent_id(), agent_foo.step(model_world));

View File

@@ -28,25 +28,27 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
TEST(AgentID, DefaultConstructor) {
const kami::AgentID agent_id_foo;
const kami::AgentID agent_id_bar;
const AgentID agent_id_foo;
const AgentID agent_id_bar;
EXPECT_EQ(agent_id_foo, agent_id_foo);
EXPECT_NE(agent_id_foo, agent_id_bar);
}
TEST(AgentID, to_string) {
const kami::AgentID agent_id_foo;
const kami::AgentID agent_id_bar;
const AgentID agent_id_foo;
const AgentID agent_id_bar;
EXPECT_THAT(agent_id_foo.to_string(), testing::MatchesRegex("[0-9]+"));
EXPECT_THAT(agent_id_bar.to_string(), testing::MatchesRegex("[0-9]+"));
}
TEST(AgentID, Equality) {
const kami::AgentID agent_id_foo;
const kami::AgentID agent_id_bar;
const AgentID agent_id_foo;
const AgentID agent_id_bar;
EXPECT_TRUE(agent_id_foo == agent_id_foo);
EXPECT_TRUE(agent_id_bar == agent_id_bar);
@@ -54,16 +56,16 @@ TEST(AgentID, Equality) {
}
TEST(AgentID, Inequality) {
const kami::AgentID agent_id_foo;
const kami::AgentID agent_id_bar;
const AgentID agent_id_foo;
const AgentID agent_id_bar;
EXPECT_TRUE(agent_id_foo != agent_id_bar);
EXPECT_FALSE(agent_id_bar != agent_id_bar);
}
TEST(AgentID, Ordering) {
const kami::AgentID agent_id_foo;
const kami::AgentID agent_id_bar;
const AgentID agent_id_foo;
const AgentID agent_id_bar;
EXPECT_TRUE(agent_id_foo < agent_id_bar);
EXPECT_FALSE(agent_id_bar < agent_id_foo);

View File

@@ -0,0 +1,107 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <kami/grid1d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
TEST(GridCoord1D, DefaultConstructor) {
const GridCoord1D gridcoord1d_foo(0);
const GridCoord1D gridcoord1d_bar(1);
const GridCoord1D gridcoord1d_baz(-1);
const GridCoord1D gridcoord1d_qux(0);
EXPECT_EQ(gridcoord1d_foo, gridcoord1d_foo);
EXPECT_EQ(gridcoord1d_foo, gridcoord1d_qux);
EXPECT_NE(gridcoord1d_foo, gridcoord1d_bar);
EXPECT_NE(gridcoord1d_foo, gridcoord1d_baz);
EXPECT_NE(gridcoord1d_bar, gridcoord1d_baz);
}
TEST(GridCoord1D, to_string) {
const GridCoord1D gridcoord1d_foo(0);
const GridCoord1D gridcoord1d_bar(1);
const GridCoord1D gridcoord1d_baz(-1);
EXPECT_THAT(gridcoord1d_foo.to_string(), "(0)");
EXPECT_THAT(gridcoord1d_bar.to_string(), "(1)");
EXPECT_THAT(gridcoord1d_baz.to_string(), "(-1)");
}
TEST(GridCoord1D, Equality) {
const GridCoord1D gridcoord1d_foo(0);
const GridCoord1D gridcoord1d_bar(1);
const GridCoord1D gridcoord1d_baz(-1);
const GridCoord1D gridcoord1d_qux(0);
EXPECT_TRUE(gridcoord1d_foo == gridcoord1d_foo);
EXPECT_TRUE(gridcoord1d_foo == gridcoord1d_qux);
EXPECT_FALSE(gridcoord1d_foo == gridcoord1d_bar);
EXPECT_FALSE(gridcoord1d_foo == gridcoord1d_baz);
EXPECT_FALSE(gridcoord1d_bar == gridcoord1d_baz);
}
TEST(GridCoord1D, Inequality) {
const GridCoord1D gridcoord1d_foo(0);
const GridCoord1D gridcoord1d_bar(1);
const GridCoord1D gridcoord1d_baz(-1);
const GridCoord1D gridcoord1d_qux(0);
EXPECT_FALSE(gridcoord1d_foo != gridcoord1d_foo);
EXPECT_FALSE(gridcoord1d_foo != gridcoord1d_qux);
EXPECT_TRUE(gridcoord1d_foo != gridcoord1d_bar);
EXPECT_TRUE(gridcoord1d_foo != gridcoord1d_baz);
EXPECT_TRUE(gridcoord1d_bar != gridcoord1d_baz);
}
TEST(GridCoord1D, get_x_location) {
const GridCoord1D gridcoord1d_foo(0);
const GridCoord1D gridcoord1d_bar(1);
const GridCoord1D gridcoord1d_baz(-1);
const GridCoord1D gridcoord1d_qux(0);
EXPECT_TRUE(gridcoord1d_foo.get_x_location() == 0);
EXPECT_TRUE(gridcoord1d_bar.get_x_location() == 1);
EXPECT_TRUE(gridcoord1d_baz.get_x_location() == -1);
EXPECT_TRUE(gridcoord1d_foo.get_x_location() == gridcoord1d_foo.get_x_location());
EXPECT_TRUE(gridcoord1d_foo.get_x_location() == gridcoord1d_qux.get_x_location());
EXPECT_FALSE(gridcoord1d_foo.get_x_location() == gridcoord1d_bar.get_x_location());
EXPECT_FALSE(gridcoord1d_foo.get_x_location() == gridcoord1d_baz.get_x_location());
EXPECT_FALSE(gridcoord1d_bar.get_x_location() == gridcoord1d_baz.get_x_location());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,149 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <kami/grid2d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
TEST(GridCoord2D, DefaultConstructor) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_EQ(gridcoord2d_foo, gridcoord2d_foo);
EXPECT_NE(gridcoord2d_foo, gridcoord2d_bar);
EXPECT_NE(gridcoord2d_foo, gridcoord2d_baz);
EXPECT_NE(gridcoord2d_bar, gridcoord2d_baz);
EXPECT_NE(gridcoord2d_foo, gridcoord2d_qux);
EXPECT_NE(gridcoord2d_foo, gridcoord2d_qu2);
}
TEST(GridCoord2D, to_string) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_THAT(gridcoord2d_foo.to_string(), "(0, 0)");
EXPECT_THAT(gridcoord2d_bar.to_string(), "(1, 1)");
EXPECT_THAT(gridcoord2d_baz.to_string(), "(-1, -1)");
EXPECT_THAT(gridcoord2d_qux.to_string(), "(0, 1)");
EXPECT_THAT(gridcoord2d_qu2.to_string(), "(1, 0)");
}
TEST(GridCoord2D, Equality) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_TRUE(gridcoord2d_foo == gridcoord2d_foo);
EXPECT_FALSE(gridcoord2d_foo == gridcoord2d_bar);
EXPECT_FALSE(gridcoord2d_foo == gridcoord2d_baz);
EXPECT_FALSE(gridcoord2d_bar == gridcoord2d_baz);
EXPECT_FALSE(gridcoord2d_foo == gridcoord2d_qux);
EXPECT_FALSE(gridcoord2d_qux == gridcoord2d_qu2);
EXPECT_FALSE(gridcoord2d_qux == gridcoord2d_qu2);
}
TEST(GridCoord2D, Inequality) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_FALSE(gridcoord2d_foo != gridcoord2d_foo);
EXPECT_TRUE(gridcoord2d_foo != gridcoord2d_qux);
EXPECT_TRUE(gridcoord2d_foo != gridcoord2d_bar);
EXPECT_TRUE(gridcoord2d_foo != gridcoord2d_baz);
EXPECT_TRUE(gridcoord2d_bar != gridcoord2d_baz);
EXPECT_TRUE(gridcoord2d_qux != gridcoord2d_qu2);
}
TEST(GridCoord2D, get_x_location) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_TRUE(gridcoord2d_foo.get_x_location() == 0);
EXPECT_TRUE(gridcoord2d_bar.get_x_location() == 1);
EXPECT_TRUE(gridcoord2d_baz.get_x_location() == -1);
EXPECT_FALSE(gridcoord2d_qux.get_x_location() == -1);
EXPECT_FALSE(gridcoord2d_qu2.get_x_location() == -1);
EXPECT_TRUE(gridcoord2d_foo.get_x_location() == gridcoord2d_foo.get_x_location());
EXPECT_TRUE(gridcoord2d_foo.get_x_location() == gridcoord2d_qux.get_x_location());
EXPECT_TRUE(gridcoord2d_bar.get_x_location() == gridcoord2d_qu2.get_x_location());
EXPECT_FALSE(gridcoord2d_foo.get_x_location() == gridcoord2d_bar.get_x_location());
EXPECT_FALSE(gridcoord2d_foo.get_x_location() == gridcoord2d_baz.get_x_location());
EXPECT_FALSE(gridcoord2d_bar.get_x_location() == gridcoord2d_baz.get_x_location());
EXPECT_FALSE(gridcoord2d_foo.get_x_location() == gridcoord2d_baz.get_x_location());
EXPECT_FALSE(gridcoord2d_qux.get_x_location() == gridcoord2d_qu2.get_x_location());
}
TEST(GridCoord2D, get_y_location) {
const GridCoord2D gridcoord2d_foo(0, 0);
const GridCoord2D gridcoord2d_bar(1, 1);
const GridCoord2D gridcoord2d_baz(-1, -1);
const GridCoord2D gridcoord2d_qux(0, 1);
const GridCoord2D gridcoord2d_qu2(1, 0);
EXPECT_TRUE(gridcoord2d_foo.get_y_location() == 0);
EXPECT_TRUE(gridcoord2d_bar.get_y_location() == 1);
EXPECT_TRUE(gridcoord2d_baz.get_y_location() == -1);
EXPECT_FALSE(gridcoord2d_qux.get_y_location() == -1);
EXPECT_FALSE(gridcoord2d_qu2.get_y_location() == -1);
EXPECT_TRUE(gridcoord2d_foo.get_y_location() == gridcoord2d_foo.get_y_location());
EXPECT_TRUE(gridcoord2d_bar.get_y_location() == gridcoord2d_qux.get_y_location());
EXPECT_FALSE(gridcoord2d_foo.get_y_location() == gridcoord2d_bar.get_y_location());
EXPECT_FALSE(gridcoord2d_foo.get_y_location() == gridcoord2d_baz.get_y_location());
EXPECT_FALSE(gridcoord2d_bar.get_y_location() == gridcoord2d_baz.get_y_location());
EXPECT_FALSE(gridcoord2d_foo.get_y_location() == gridcoord2d_baz.get_y_location());
EXPECT_FALSE(gridcoord2d_qux.get_y_location() == gridcoord2d_qu2.get_y_location());
EXPECT_FALSE(gridcoord2d_bar.get_y_location() == gridcoord2d_qu2.get_y_location());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -33,20 +33,19 @@
#include <gtest/gtest.h>
class TestAgent : public kami::Agent {
using namespace kami;
using namespace std;
class TestAgent : public Agent {
public:
kami::AgentID step(std::shared_ptr<kami::Model> model) override {
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public kami::Model {
class TestModel : public Model {
public:
std::shared_ptr<kami::Model> step() override {
return shared_from_this();
}
std::shared_ptr<kami::Model> run(unsigned int) override {
shared_ptr<Model> step() {
return shared_from_this();
}
};
@@ -61,16 +60,16 @@ TEST(Model, DefaultConstructor) {
}
TEST(Model, set_population) {
auto model_foo = std::make_shared<TestModel>();
auto popul_foo = std::make_shared<kami::Population>();
auto model_foo = make_shared<TestModel>();
auto popul_foo = make_shared<Population>();
auto popul_bar = model_foo->set_population(popul_foo);
EXPECT_EQ(popul_foo, popul_bar);
}
TEST(Model, get_population) {
auto model_foo = std::make_shared<TestModel>();
auto popul_foo = std::make_shared<kami::Population>();
auto model_foo = make_shared<TestModel>();
auto popul_foo = make_shared<Population>();
auto popul_nul = model_foo->get_population();
@@ -83,16 +82,16 @@ TEST(Model, get_population) {
}
TEST(Model, set_scheduler) {
auto model_foo = std::make_shared<TestModel>();
auto sched_foo = std::make_shared<kami::SequentialScheduler>();
auto model_foo = make_shared<TestModel>();
auto sched_foo = make_shared<SequentialScheduler>();
auto sched_bar = model_foo->set_scheduler(sched_foo);
EXPECT_EQ(sched_foo, sched_bar);
}
TEST(Model, get_scheduler) {
auto model_foo = std::make_shared<TestModel>();
auto sched_foo = std::make_shared<kami::SequentialScheduler>();
auto model_foo = make_shared<TestModel>();
auto sched_foo = make_shared<SequentialScheduler>();
auto sched_nul = model_foo->get_scheduler();
EXPECT_FALSE(sched_nul);
@@ -106,16 +105,16 @@ TEST(Model, get_scheduler) {
}
TEST(Model, set_domain) {
auto model_foo = std::make_shared<TestModel>();
auto grid2_foo = std::make_shared<kami::MultiGrid2D>(10, 10, true, true);
auto model_foo = make_shared<TestModel>();
auto grid2_foo = make_shared<MultiGrid2D>(10, 10, true, true);
auto grid2_bar = model_foo->set_domain(grid2_foo);
EXPECT_EQ(grid2_foo, grid2_bar);
}
TEST(Model, get_domain) {
auto model_foo = std::make_shared<TestModel>();
auto grid2_foo = std::make_shared<kami::MultiGrid2D>(10, 10, true, true);
auto model_foo = make_shared<TestModel>();
auto grid2_foo = make_shared<MultiGrid2D>(10, 10, true, true);
auto grid2_nul = model_foo->get_domain();
EXPECT_FALSE(grid2_nul);

View File

@@ -23,25 +23,33 @@
* SOFTWARE.
*/
#include <algorithm>
#include <iterator>
#include <set>
#include <unordered_set>
#include <kami/agent.h>
#include <kami/multigrid1d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
TEST(MultiGrid1D, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
kami::MultiGrid1D multigrid1d_foo(10, true);
MultiGrid1D multigrid1d_foo(10, true);
);
}
TEST(MultiGrid1D, add_agent) {
kami::MultiGrid1D multigrid1d_foo(10, true);
const kami::AgentID agent_id_foo, agent_id_bar;
const kami::GridCoord1D coord2(2), coord3(3);
MultiGrid1D multigrid1d_foo(10, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
auto agent_id_baz = multigrid1d_foo.add_agent(agent_id_foo, coord2);
@@ -60,6 +68,398 @@ TEST(MultiGrid1D, add_agent) {
}
}
TEST(MultiGrid1D, delete_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_bar);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_bar, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.delete_agent(agent_id_bar, coord3);
EXPECT_FALSE(agent_id_baz);
}
}
TEST(MultiGrid1D, is_location_valid) {
MultiGrid1D multigrid1d_foo(10, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coordm1(-1), coord0(0), coord2(2), coord3(3), coord10(10), coord100(100);
{
EXPECT_TRUE(multigrid1d_foo.is_location_valid(coord0));
EXPECT_TRUE(multigrid1d_foo.is_location_valid(coord2));
EXPECT_TRUE(multigrid1d_foo.is_location_valid(coord2));
EXPECT_FALSE(multigrid1d_foo.is_location_valid(coordm1));
EXPECT_FALSE(multigrid1d_foo.is_location_valid(coord10));
EXPECT_FALSE(multigrid1d_foo.is_location_valid(coord100));
}
}
TEST(MultiGrid1D, is_location_empty) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
MultiGrid1D multigrid1d_foo(10, true);
EXPECT_TRUE(multigrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid1d_foo.is_location_empty(coord3));
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
EXPECT_FALSE(multigrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid1d_foo.is_location_empty(coord3));
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
EXPECT_FALSE(multigrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid1d_foo.is_location_empty(coord3));
}
}
TEST(MultiGrid1D, move_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3), coord7(7), coord10(10);
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid1d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid1d_foo.move_agent(agent_id_foo, coord10);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.move_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid1d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
}
TEST(MultiGrid1D, get_neighborhood) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord0(0), coord1(1), coord2(2), coord3(3), coord9(9);
{
MultiGrid1D multigrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = multigrid1d_foo.get_neighborhood(coord0, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = multigrid1d_foo.get_neighborhood(coord1, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord1});
auto rval = multigrid1d_foo.get_neighborhood(coord0, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = multigrid1d_foo.get_neighborhood(coord1, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord1, coord9});
auto rval = multigrid1d_foo.get_neighborhood(coord0, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = multigrid1d_foo.get_neighborhood(coord1, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord1});
auto rval = multigrid1d_foo.get_neighborhood(coord0, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = multigrid1d_foo.get_neighborhood(coord1, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_FALSE(rval);
}
{
MultiGrid1D multigrid1d_foo(10, true);
multigrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
multigrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
multigrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord0, coord1});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
multigrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
multigrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord1, coord9});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
multigrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
multigrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord1});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, false);
multigrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = multigrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(MultiGrid1D, get_location_by_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
MultiGrid1D multigrid1d_foo(10, true);
EXPECT_FALSE(multigrid1d_foo.get_location_by_agent(agent_id_foo));
EXPECT_FALSE(multigrid1d_foo.get_location_by_agent(agent_id_bar));
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord2));
auto local = multigrid1d_foo.get_location_by_agent(agent_id_foo);
EXPECT_TRUE(local);
EXPECT_EQ(local, coord2);
EXPECT_FALSE(multigrid1d_foo.get_location_by_agent(agent_id_bar));
}
}
TEST(MultiGrid1D, get_location_contents) {
const AgentID agent_id_foo, agent_id_bar, agent_id_baz;
const GridCoord1D coord0(0), coord1(1), coord9(9), coord10(10);
{
MultiGrid1D multigrid1d_foo(10, true);
auto agent_list_foo = multigrid1d_foo.get_location_contents(coord10);
EXPECT_FALSE(agent_list_foo);
}
{
MultiGrid1D multigrid1d_foo(10, true);
auto agent_list_foo = multigrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(agent_list_foo);
EXPECT_TRUE(agent_list_foo.value()->empty());
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord1));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord1));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_baz, coord1));
auto tval = set<AgentID>({agent_id_foo, agent_id_bar, agent_id_baz});
auto rval = multigrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid1D multigrid1d_foo(10, true);
static_cast<void>(multigrid1d_foo.add_agent(agent_id_foo, coord1));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_bar, coord1));
static_cast<void>(multigrid1d_foo.add_agent(agent_id_baz, coord9));
auto tval = set<AgentID>({agent_id_foo, agent_id_bar});
auto rval = multigrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);

View File

@@ -0,0 +1,728 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <algorithm>
#include <iterator>
#include <set>
#include <unordered_set>
#include <kami/agent.h>
#include <kami/multigrid2d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
TEST(MultiGrid2D, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
MultiGrid2D multigrid2d_foo(10, 10, true, true);
);
}
TEST(MultiGrid2D, add_agent) {
MultiGrid2D multigrid2d_foo(10, 10, true, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
auto agent_id_baz = multigrid2d_foo.add_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
auto agent_id_baz = multigrid2d_foo.add_agent(agent_id_bar, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
{
auto agent_id_baz = multigrid2d_foo.add_agent(agent_id_bar, coord3);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
}
TEST(MultiGrid2D, delete_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_bar);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_bar, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.delete_agent(agent_id_bar, coord3);
EXPECT_FALSE(agent_id_baz);
}
}
TEST(MultiGrid2D, is_location_valid) {
MultiGrid2D multigrid2d_foo(10, 10, true, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coordm1(-1, -1), coord0(0, 0), coord2(2, 5), coord3(3, 7), coord10(10, 5), coord100(100, 100);
{
EXPECT_TRUE(multigrid2d_foo.is_location_valid(coord0));
EXPECT_TRUE(multigrid2d_foo.is_location_valid(coord2));
EXPECT_TRUE(multigrid2d_foo.is_location_valid(coord2));
EXPECT_FALSE(multigrid2d_foo.is_location_valid(coordm1));
EXPECT_FALSE(multigrid2d_foo.is_location_valid(coord10));
EXPECT_FALSE(multigrid2d_foo.is_location_valid(coord100));
}
}
TEST(MultiGrid2D, is_location_empty) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
EXPECT_TRUE(multigrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid2d_foo.is_location_empty(coord3));
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
EXPECT_FALSE(multigrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid2d_foo.is_location_empty(coord3));
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
EXPECT_FALSE(multigrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(multigrid2d_foo.is_location_empty(coord3));
}
}
TEST(MultiGrid2D, move_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7), coord7(7, 2), coord10(10, 5);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid2d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = multigrid2d_foo.move_agent(agent_id_foo, coord10);
EXPECT_FALSE(agent_id_baz);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.move_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(multigrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = multigrid2d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
}
TEST(MultiGrid2D, get_neighborhood_VonNeumann) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord0(0, 0), coord1(1, 1), coord2(2, 5), coord3(3, 7), coord9(9, 4);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{0, 1},
{9, 0},
{0, 9},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_FALSE(rval);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{9, 0},
{0, 9},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 2},
{2, 1},
{1, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 2},
{2, 1},
{1, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(MultiGrid2D, get_neighborhood_Moore) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord0(0, 0), coord1(1, 1), coord2(2, 5), coord3(3, 7), coord9(9, 4);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 1},
{0, 1},
{9, 0},
{1, 9},
{0, 9},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 1},
{0, 1},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_FALSE(rval);
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 1},
{0, 1},
{9, 0},
{1, 9},
{0, 9},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 1},
{0, 1},
{1, 0},
{0, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{2, 0},
{0, 1},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
MultiGrid2D multigrid2d_foo(10, 10, false, false);
multigrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{2, 0},
{0, 1},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0}});
auto rval = multigrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(MultiGrid2D, get_location_by_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
EXPECT_FALSE(multigrid2d_foo.get_location_by_agent(agent_id_foo));
EXPECT_FALSE(multigrid2d_foo.get_location_by_agent(agent_id_bar));
}
{
MultiGrid2D multigrid2d_foo(10, 10, true, true);
static_cast<void>(multigrid2d_foo.add_agent(agent_id_foo, coord2));
auto local = multigrid2d_foo.get_location_by_agent(agent_id_foo);
EXPECT_TRUE(local);
EXPECT_EQ(local, coord2);
EXPECT_FALSE(multigrid2d_foo.get_location_by_agent(agent_id_bar));
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,197 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <kami/agent.h>
#include <kami/population.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
class TestAgent : public Agent {
private:
int _x;
public:
explicit TestAgent(int x) : _x(x) {};
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
int getval() {
return _x;
}
};
TEST(Population, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
const Population population_foo;
);
}
TEST(Population, add_agent) {
Population population_foo;
auto agent_foo = make_shared<TestAgent>(8675309);
auto agent_bar = make_shared<TestAgent>(1729);
{
auto agent_id_baz = population_foo.add_agent(agent_foo);
EXPECT_EQ(agent_id_baz, agent_foo->get_agent_id());
}
{
auto agent_id_baz = population_foo.add_agent(agent_bar);
EXPECT_EQ(agent_id_baz, agent_bar->get_agent_id());
}
{
auto agent_id_baz = population_foo.add_agent(agent_foo);
EXPECT_EQ(agent_id_baz, agent_foo->get_agent_id());
auto agent_id_qux = population_foo.add_agent(agent_bar);
EXPECT_EQ(agent_id_qux, agent_bar->get_agent_id());
}
}
TEST(Population, get_agent_by_id) {
auto agent_foo = make_shared<TestAgent>(8675309);
auto agent_bar = make_shared<TestAgent>(1729);
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
auto agent_baz_opt = population_foo.get_agent_by_id(agent_foo->get_agent_id());
EXPECT_TRUE(agent_baz_opt);
auto agent_baz = dynamic_pointer_cast<TestAgent>(agent_baz_opt.value());
EXPECT_EQ(agent_baz->getval(), 8675309);
}
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
auto agent_baz_opt = population_foo.get_agent_by_id(agent_bar->get_agent_id());
EXPECT_FALSE(agent_baz_opt);
}
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
static_cast<void>(population_foo.add_agent(agent_bar));
auto agent_baz_opt = population_foo.get_agent_by_id(agent_foo->get_agent_id());
EXPECT_TRUE(agent_baz_opt);
auto agent_baz = dynamic_pointer_cast<TestAgent>(agent_baz_opt.value());
EXPECT_EQ(agent_baz->getval(), 8675309);
auto agent_qux_opt = population_foo.get_agent_by_id(agent_bar->get_agent_id());
EXPECT_TRUE(agent_qux_opt);
auto agent_qux = dynamic_pointer_cast<TestAgent>(agent_qux_opt.value());
EXPECT_EQ(agent_qux->getval(), 1729);
}
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
static_cast<void>(population_foo.add_agent(agent_bar));
auto agent_qux_opt = population_foo.get_agent_by_id(agent_bar->get_agent_id());
EXPECT_TRUE(agent_qux_opt);
auto agent_qux = dynamic_pointer_cast<TestAgent>(agent_qux_opt.value());
EXPECT_EQ(agent_qux->getval(), 1729);
auto agent_baz_opt = population_foo.get_agent_by_id(agent_foo->get_agent_id());
EXPECT_TRUE(agent_baz_opt);
auto agent_baz = dynamic_pointer_cast<TestAgent>(agent_baz_opt.value());
EXPECT_EQ(agent_baz->getval(), 8675309);
}
}
TEST(Population, get_agent_list) {
auto agent_foo = make_shared<TestAgent>(8675309);
auto agent_bar = make_shared<TestAgent>(1729);
auto agent_baz = make_shared<TestAgent>(4104);
auto agent_qux = make_shared<TestAgent>(196);
{
Population population_foo;
auto tval = make_shared<vector<AgentID>>();
auto rval = population_foo.get_agent_list();
EXPECT_EQ(*tval, *rval);
}
{
Population population_foo;
auto tval = make_shared<vector<AgentID>>();
auto rval = population_foo.get_agent_list();
tval->push_back(agent_foo->get_agent_id());
EXPECT_NE(*tval, *rval);
}
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
static_cast<void>(population_foo.add_agent(agent_bar));
auto tval = make_shared<vector<AgentID>>();
auto uval = make_shared<vector<AgentID>>();
auto rval = population_foo.get_agent_list();
tval->push_back(agent_foo->get_agent_id());
tval->push_back(agent_bar->get_agent_id());
EXPECT_EQ(*tval, *rval);
// Ordering matters
uval->push_back(agent_bar->get_agent_id());
uval->push_back(agent_foo->get_agent_id());
EXPECT_NE(*uval, *rval);
}
{
Population population_foo;
static_cast<void>(population_foo.add_agent(agent_foo));
static_cast<void>(population_foo.add_agent(agent_bar));
static_cast<void>(population_foo.add_agent(agent_baz));
static_cast<void>(population_foo.add_agent(agent_qux));
auto tval = make_shared<vector<AgentID>>();
auto rval = population_foo.get_agent_list();
tval->push_back(agent_foo->get_agent_id());
tval->push_back(agent_bar->get_agent_id());
tval->push_back(agent_baz->get_agent_id());
tval->push_back(agent_qux->get_agent_id());
EXPECT_EQ(*tval, *rval);
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

152
test/unit-kami-random.cc Normal file
View File

@@ -0,0 +1,152 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <memory>
#include <random>
#include <set>
#include <utility>
#include <vector>
#include <kami/agent.h>
#include <kami/population.h>
#include <kami/random.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
class TestAgent : public Agent {
public:
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public Model {
public:
optional<shared_ptr<vector<AgentID>>> step() {
return _sched->step(shared_from_this());
}
optional<shared_ptr<vector<AgentID>>> step(shared_ptr<vector<AgentID>> agent_list) {
return _sched->step(shared_from_this(), move(agent_list));
}
};
class RandomSchedulerTest : public ::testing::Test {
protected:
shared_ptr<TestModel> mod = nullptr;
shared_ptr<ranlux24> rng = nullptr;
void SetUp() override {
mod = make_shared<TestModel>();
rng = make_shared<ranlux24>();
auto popul_foo = make_shared<Population>();
auto sched_foo = make_shared<RandomScheduler>(rng);
// Domain is not required for this test
static_cast<void>(mod->set_population(popul_foo));
static_cast<void>(mod->set_scheduler(sched_foo));
for (auto i = 0; i < 10; i++) {
auto agent_foo = make_shared<TestAgent>();
static_cast<void>(popul_foo->add_agent(agent_foo));
}
}
};
TEST(RandomScheduler, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
const RandomScheduler sched_foo;
);
}
TEST_F(RandomSchedulerTest, step_interface1) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
// Sort both return values and just make sure all of them all the same...
// We cannot test permutation since, well, you know...
set<AgentID> tval_set = set(tval->begin(), tval->end());
set<AgentID> rval_set = set(rval.value()->begin(), rval.value()->end());
EXPECT_EQ(tval_set, rval_set);
}
TEST_F(RandomSchedulerTest, step_interface2) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step(tval);
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
set<AgentID> tval_set = set(tval->begin(), tval->end());
set<AgentID> rval_set = set(rval.value()->begin(), rval.value()->end());
EXPECT_EQ(tval_set, rval_set);
}
TEST_F(RandomSchedulerTest, step_10000) {
auto tval = mod->get_population().value()->get_agent_list();
set<AgentID> tval_set = set(tval->begin(), tval->end());
// Do it a lot...
for (auto i = 0; i < 10000; i++) {
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
set<AgentID> rval_set = set(rval.value()->begin(), rval.value()->end());
EXPECT_EQ(tval_set, rval_set);
}
}
TEST_F(RandomSchedulerTest, get_rng) {
auto rval = static_pointer_cast<RandomScheduler>(mod->get_scheduler().value())->get_rng();
EXPECT_EQ(rng, rval);
}
TEST_F(RandomSchedulerTest, set_rng) {
auto new_rng = make_shared<ranlux24>();
auto rval1 = static_pointer_cast<RandomScheduler>(mod->get_scheduler().value())->get_rng();
static_cast<void>(static_pointer_cast<RandomScheduler>(mod->get_scheduler().value())->set_rng(new_rng));
auto rval2 = static_pointer_cast<RandomScheduler>(mod->get_scheduler().value())->get_rng();
EXPECT_EQ(new_rng, rval2);
EXPECT_NE(new_rng, rval1);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,121 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <memory>
#include <utility>
#include <vector>
#include <kami/agent.h>
#include <kami/population.h>
#include <kami/sequential.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
class TestAgent : public Agent {
public:
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public Model {
public:
optional<shared_ptr<vector<AgentID>>> step() {
return _sched->step(shared_from_this());
}
optional<shared_ptr<vector<AgentID>>> step(shared_ptr<vector<AgentID>> agent_list) {
return _sched->step(shared_from_this(), move(agent_list));
}
};
class SequentialSchedulerTest : public ::testing::Test {
protected:
shared_ptr<TestModel> mod = nullptr;
void SetUp() override {
mod = make_shared<TestModel>();
auto popul_foo = make_shared<Population>();
auto sched_foo = make_shared<SequentialScheduler>();
// Domain is not required for this test
static_cast<void>(mod->set_population(popul_foo));
static_cast<void>(mod->set_scheduler(sched_foo));
for (auto i = 0; i < 10; i++) {
auto agent_foo = make_shared<TestAgent>();
static_cast<void>(popul_foo->add_agent(agent_foo));
}
}
};
TEST(SequentialScheduler, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
const SequentialScheduler sched_foo;
);
}
TEST_F(SequentialSchedulerTest, step_interface1) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
TEST_F(SequentialSchedulerTest, step_interface2) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step(tval);
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
TEST_F(SequentialSchedulerTest, step_10000) {
auto tval = mod->get_population().value()->get_agent_list();
// Do it a lot...
for (auto i = 0; i < 10000; i++) {
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,465 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <algorithm>
#include <iterator>
#include <set>
#include <unordered_set>
#include <kami/agent.h>
#include <kami/sologrid1d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
TEST(SoloGrid1D, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
SoloGrid1D sologrid1d_foo(10, true);
);
}
TEST(SoloGrid1D, add_agent) {
SoloGrid1D sologrid1d_foo(10, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
auto agent_id_baz = sologrid1d_foo.add_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
auto agent_id_baz = sologrid1d_foo.add_agent(agent_id_bar, coord2);
EXPECT_FALSE(agent_id_baz);
}
{
auto agent_id_baz = sologrid1d_foo.add_agent(agent_id_bar, coord3);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
}
TEST(SoloGrid1D, delete_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_bar);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_bar, coord2);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.delete_agent(agent_id_bar, coord3);
EXPECT_FALSE(agent_id_baz);
}
}
TEST(SoloGrid1D, is_location_valid) {
SoloGrid1D sologrid1d_foo(10, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coordm1(-1), coord0(0), coord2(2), coord3(3), coord10(10), coord100(100);
{
EXPECT_TRUE(sologrid1d_foo.is_location_valid(coord0));
EXPECT_TRUE(sologrid1d_foo.is_location_valid(coord2));
EXPECT_TRUE(sologrid1d_foo.is_location_valid(coord2));
EXPECT_FALSE(sologrid1d_foo.is_location_valid(coordm1));
EXPECT_FALSE(sologrid1d_foo.is_location_valid(coord10));
EXPECT_FALSE(sologrid1d_foo.is_location_valid(coord100));
}
}
TEST(SoloGrid1D, is_location_empty) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
SoloGrid1D sologrid1d_foo(10, true);
EXPECT_TRUE(sologrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid1d_foo.is_location_empty(coord3));
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
EXPECT_FALSE(sologrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid1d_foo.is_location_empty(coord3));
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
EXPECT_FALSE(sologrid1d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid1d_foo.is_location_empty(coord3));
}
}
TEST(SoloGrid1D, move_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3), coord7(7), coord10(10);
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid1d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid1d_foo.move_agent(agent_id_foo, coord10);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.move_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid1d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
}
TEST(SoloGrid1D, get_neighborhood) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord0(0), coord1(1), coord2(2), coord3(3), coord9(9);
{
SoloGrid1D sologrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = sologrid1d_foo.get_neighborhood(coord0, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = sologrid1d_foo.get_neighborhood(coord1, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord1});
auto rval = sologrid1d_foo.get_neighborhood(coord0, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = sologrid1d_foo.get_neighborhood(coord1, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord1, coord9});
auto rval = sologrid1d_foo.get_neighborhood(coord0, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = sologrid1d_foo.get_neighborhood(coord1, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord1});
auto rval = sologrid1d_foo.get_neighborhood(coord0, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = sologrid1d_foo.get_neighborhood(coord1, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_FALSE(rval);
}
{
SoloGrid1D sologrid1d_foo(10, true);
sologrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord9});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
sologrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
sologrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord0, coord1});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
sologrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord1, coord2});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, true);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
sologrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord1, coord9});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
sologrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
sologrid1d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord1D>({coord1});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, false);
sologrid1d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord1D>({coord0, coord2});
auto rval = sologrid1d_foo.get_neighborhood(agent_id_foo, false);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(SoloGrid1D, get_location_by_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord1D coord2(2), coord3(3);
{
SoloGrid1D sologrid1d_foo(10, true);
EXPECT_FALSE(sologrid1d_foo.get_location_by_agent(agent_id_foo));
EXPECT_FALSE(sologrid1d_foo.get_location_by_agent(agent_id_bar));
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord2));
auto local = sologrid1d_foo.get_location_by_agent(agent_id_foo);
EXPECT_TRUE(local);
EXPECT_EQ(local, coord2);
EXPECT_FALSE(sologrid1d_foo.get_location_by_agent(agent_id_bar));
}
}
TEST(SoloGrid1D, get_location_contents) {
const AgentID agent_id_foo, agent_id_bar, agent_id_baz;
const GridCoord1D coord0(0), coord1(1), coord9(9), coord10(10);
{
SoloGrid1D sologrid1d_foo(10, true);
auto agent_list_foo = sologrid1d_foo.get_location_contents(coord10);
EXPECT_FALSE(agent_list_foo);
}
{
SoloGrid1D sologrid1d_foo(10, true);
auto agent_list_foo = sologrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(agent_list_foo);
EXPECT_TRUE(agent_list_foo.value()->empty());
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord1));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord1));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_baz, coord1));
auto tval = set<AgentID>({agent_id_foo});
auto rval = sologrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid1D sologrid1d_foo(10, true);
static_cast<void>(sologrid1d_foo.add_agent(agent_id_foo, coord1));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_bar, coord1));
static_cast<void>(sologrid1d_foo.add_agent(agent_id_baz, coord9));
auto tval = set<AgentID>({agent_id_foo});
auto rval = sologrid1d_foo.get_location_contents(coord1);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,725 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <algorithm>
#include <iterator>
#include <set>
#include <unordered_set>
#include <kami/agent.h>
#include <kami/sologrid2d.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
TEST(SoloGrid2D, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
SoloGrid2D sologrid2d_foo(10, 10, true, true);
);
}
TEST(SoloGrid2D, add_agent) {
SoloGrid2D sologrid2d_foo(10, 10, true, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
auto agent_id_baz = sologrid2d_foo.add_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
auto agent_id_baz = sologrid2d_foo.add_agent(agent_id_bar, coord2);
EXPECT_FALSE(agent_id_baz);
}
{
auto agent_id_baz = sologrid2d_foo.add_agent(agent_id_bar, coord3);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_bar);
}
}
TEST(SoloGrid2D, delete_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_bar);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_bar, coord2);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_foo, coord3);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.delete_agent(agent_id_bar, coord3);
EXPECT_FALSE(agent_id_baz);
}
}
TEST(SoloGrid2D, is_location_valid) {
SoloGrid2D sologrid2d_foo(10, 10, true, true);
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coordm1(-1, -1), coord0(0, 0), coord2(2, 5), coord3(3, 7), coord10(10, 5), coord100(100, 100);
{
EXPECT_TRUE(sologrid2d_foo.is_location_valid(coord0));
EXPECT_TRUE(sologrid2d_foo.is_location_valid(coord2));
EXPECT_TRUE(sologrid2d_foo.is_location_valid(coord2));
EXPECT_FALSE(sologrid2d_foo.is_location_valid(coordm1));
EXPECT_FALSE(sologrid2d_foo.is_location_valid(coord10));
EXPECT_FALSE(sologrid2d_foo.is_location_valid(coord100));
}
}
TEST(SoloGrid2D, is_location_empty) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
EXPECT_TRUE(sologrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid2d_foo.is_location_empty(coord3));
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
EXPECT_FALSE(sologrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid2d_foo.is_location_empty(coord3));
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
EXPECT_FALSE(sologrid2d_foo.is_location_empty(coord2));
EXPECT_TRUE(sologrid2d_foo.is_location_empty(coord3));
}
}
TEST(SoloGrid2D, move_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7), coord7(7, 2), coord10(10, 5);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid2d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto agent_id_baz = sologrid2d_foo.move_agent(agent_id_foo, coord10);
EXPECT_FALSE(agent_id_baz);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.move_agent(agent_id_foo, coord2);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
static_cast<void>(sologrid2d_foo.add_agent(agent_id_bar, coord2));
auto agent_id_baz = sologrid2d_foo.move_agent(agent_id_foo, coord7);
EXPECT_TRUE(agent_id_baz);
EXPECT_EQ(agent_id_baz.value(), agent_id_foo);
}
}
TEST(SoloGrid2D, get_neighborhood_VonNeumann) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord0(0, 0), coord1(1, 1), coord2(2, 5), coord3(3, 7), coord9(9, 4);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{0, 1},
{9, 0},
{0, 9},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_FALSE(rval);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{9, 0},
{0, 9},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{1, 2},
{2, 1},
{1, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1},
{9, 0},
{0, 9}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 2},
{2, 1},
{1, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{0, 1},
{1, 2},
{2, 1},
{1, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::VonNeumann);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(SoloGrid2D, get_neighborhood_Moore) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord0(0, 0), coord1(1, 1), coord2(2, 5), coord3(3, 7), coord9(9, 4);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 1},
{0, 1},
{9, 0},
{1, 9},
{0, 9},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 1},
{0, 1},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord1, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(coord0, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_FALSE(rval);
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 1},
{0, 1},
{9, 0},
{1, 9},
{0, 9},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 1},
{0, 1},
{1, 0},
{0, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0},
{2, 0},
{0, 1},
{1, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, true, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{9, 9},
{9, 1},
{1, 0},
{1, 1},
{0, 1},
{0, 9},
{1, 9},
{9, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{2, 0},
{0, 1},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord0);
auto tval = unordered_set<GridCoord2D>({{1, 0},
{1, 1},
{0, 1}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
{
SoloGrid2D sologrid2d_foo(10, 10, false, false);
sologrid2d_foo.add_agent(agent_id_foo, coord1);
auto tval = unordered_set<GridCoord2D>({{2, 2},
{2, 0},
{0, 1},
{0, 2},
{1, 2},
{0, 0},
{2, 1},
{1, 0}});
auto rval = sologrid2d_foo.get_neighborhood(agent_id_foo, false, GridNeighborhoodType::Moore);
EXPECT_TRUE(rval);
EXPECT_EQ(tval, *rval.value());
}
}
TEST(SoloGrid2D, get_location_by_agent) {
const AgentID agent_id_foo, agent_id_bar;
const GridCoord2D coord2(2, 5), coord3(3, 7);
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
EXPECT_FALSE(sologrid2d_foo.get_location_by_agent(agent_id_foo));
EXPECT_FALSE(sologrid2d_foo.get_location_by_agent(agent_id_bar));
}
{
SoloGrid2D sologrid2d_foo(10, 10, true, true);
static_cast<void>(sologrid2d_foo.add_agent(agent_id_foo, coord2));
auto local = sologrid2d_foo.get_location_by_agent(agent_id_foo);
EXPECT_TRUE(local);
EXPECT_EQ(local, coord2);
EXPECT_FALSE(sologrid2d_foo.get_location_by_agent(agent_id_bar));
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

125
test/unit-kami-staged.cc Normal file
View File

@@ -0,0 +1,125 @@
/*-
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <memory>
#include <utility>
#include <vector>
#include <kami/agent.h>
#include <kami/population.h>
#include <kami/staged.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace kami;
using namespace std;
class TestAgent : public StagedAgent {
public:
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
AgentID advance(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public Model {
public:
optional<shared_ptr<vector<AgentID>>> step() {
return _sched->step(shared_from_this());
}
optional<shared_ptr<vector<AgentID>>> step(shared_ptr<vector<AgentID>> agent_list) {
return _sched->step(shared_from_this(), move(agent_list));
}
};
class StagedSchedulerTest : public ::testing::Test {
protected:
shared_ptr<TestModel> mod = nullptr;
void SetUp() override {
mod = make_shared<TestModel>();
auto popul_foo = make_shared<Population>();
auto sched_foo = make_shared<StagedScheduler>();
// Domain is not required for this test
static_cast<void>(mod->set_population(popul_foo));
static_cast<void>(mod->set_scheduler(sched_foo));
for (auto i = 0; i < 10; i++) {
auto agent_foo = make_shared<TestAgent>();
static_cast<void>(popul_foo->add_agent(agent_foo));
}
}
};
TEST(StagedScheduler, DefaultConstructor) {
// There is really no way this can go wrong, but
// we add this check anyway in case of future
// changes.
EXPECT_NO_THROW(
const StagedScheduler sched_foo;
);
}
TEST_F(StagedSchedulerTest, step_interface1) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
TEST_F(StagedSchedulerTest, step_interface2) {
auto tval = mod->get_population().value()->get_agent_list();
auto rval = mod->step(tval);
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
TEST_F(StagedSchedulerTest, step_10000) {
auto tval = mod->get_population().value()->get_agent_list();
// Do it a lot...
for (auto i = 0; i < 10000; i++) {
auto rval = mod->step();
EXPECT_TRUE(rval);
EXPECT_EQ(rval.value()->size(), 10);
EXPECT_EQ(*rval.value(), *tval);
}
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -30,26 +30,21 @@
#include <gtest/gtest.h>
class TestStagedAgent : public kami::StagedAgent {
using namespace kami;
using namespace std;
class TestStagedAgent : public StagedAgent {
public:
kami::AgentID advance(std::shared_ptr<kami::Model> model) override {
AgentID advance(shared_ptr<Model> model) override {
return get_agent_id();
}
kami::AgentID step(std::shared_ptr<kami::Model> model) override {
AgentID step(shared_ptr<Model> model) override {
return get_agent_id();
}
};
class TestModel : public kami::Model {
public:
std::shared_ptr<kami::Model> step() override {
return shared_from_this();
}
std::shared_ptr<kami::Model> run(unsigned int) override {
return shared_from_this();
}
class TestModel : public Model {
};
TEST(StagedAgent, DefaultConstructor) {
@@ -71,7 +66,7 @@ TEST(StagedAgent, get_agent_id) {
TEST(StagedAgent, advance) {
TestStagedAgent agent_foo;
TestStagedAgent agent_bar;
auto model_world = std::make_shared<TestModel>();
auto model_world = make_shared<TestModel>();
EXPECT_EQ(agent_foo.get_agent_id(), agent_foo.advance(model_world));
EXPECT_NE(agent_bar.get_agent_id(), agent_foo.advance(model_world));
@@ -80,7 +75,7 @@ TEST(StagedAgent, advance) {
TEST(StagedAgent, step) {
TestStagedAgent agent_foo;
TestStagedAgent agent_bar;
auto model_world = std::make_shared<TestModel>();
auto model_world = make_shared<TestModel>();
EXPECT_EQ(agent_foo.get_agent_id(), agent_foo.step(model_world));
EXPECT_NE(agent_bar.get_agent_id(), agent_foo.step(model_world));