mirror of
https://github.com/JHUAPL/kami.git
synced 2026-01-10 20:18:00 -05:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01d8154017 | ||
|
|
c145466758 | ||
|
|
d7cd7bcfc4 | ||
|
|
98959520ea | ||
|
|
42c87ccccd | ||
|
|
ba0ae24cfc | ||
|
|
e2c825e2e6 | ||
|
|
c7f4c706cd | ||
|
|
584c2b94d8 | ||
|
|
b02efaae07 | ||
|
|
087bdadc16 | ||
|
|
2027ff05eb | ||
|
|
15647b905f | ||
|
|
f0ce59c967 | ||
|
|
7af69815f3 | ||
|
|
25febcb094 | ||
|
|
52bb8bb900 | ||
|
|
f3f2b00740 | ||
|
|
1200fb4de0 | ||
|
|
fb5d222915 | ||
|
|
30fdd46d93 | ||
|
|
f474d6feff | ||
|
|
caf6d01b58 | ||
|
|
44c541a4f8 | ||
|
|
0edd940344 | ||
|
|
10f33b5f61 | ||
|
|
b6406b86d8 | ||
|
|
54f49a732c | ||
|
|
f2601ea85f | ||
|
|
b9c7f9b605 | ||
|
|
d13960da35 |
@@ -1,10 +1,10 @@
|
||||
name: Build
|
||||
name: Build (develop)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
branches: [ develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
branches: [ develop ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
51
.github/workflows/build-main.yml
vendored
Normal file
51
.github/workflows/build-main.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Build (main)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Debug
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally
|
||||
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||
# cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Conan
|
||||
id: conan
|
||||
uses: turtlebrowser/get-conan@main
|
||||
|
||||
- name: Conan The Frogarian
|
||||
run: conan frogarian
|
||||
|
||||
- name: Conan Profile Setup
|
||||
run: |
|
||||
conan config init
|
||||
conan profile update settings.compiler.libcxx=libstdc++11 default
|
||||
|
||||
- name: Conan Install Dependencies
|
||||
run: conan install -if build .
|
||||
|
||||
- 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.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: cmake -B build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
run: cmake --build build --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Test
|
||||
# Execute tests defined by the CMake configuration.
|
||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||
run: cmake --build build --target test --config ${{env.BUILD_TYPE}}
|
||||
@@ -28,8 +28,8 @@
|
||||
cmake_minimum_required(VERSION 3.13) # GENERATOR_IS_MULTI_CONFIG
|
||||
|
||||
set(KAMI_VERSION_MAJOR 0)
|
||||
set(KAMI_VERSION_MINOR 3)
|
||||
set(KAMI_VERSION_PATCH 0)
|
||||
set(KAMI_VERSION_MINOR 4)
|
||||
set(KAMI_VERSION_PATCH 1)
|
||||
set(KAMI_VERSION_STRING ${KAMI_VERSION_MAJOR}.${KAMI_VERSION_MINOR}.${KAMI_VERSION_PATCH})
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[](https://github.com/JHUAPL/kami/actions/workflows/build.yml)
|
||||
[](https://github.com/JHUAPL/kami/actions/workflows/build.yml)
|
||||
[](https://github.com/JHUAPL/kami/actions/workflows/build-main.yml)
|
||||
[](https://github.com/JHUAPL/kami/actions/workflows/build-develop.yml)
|
||||
[](https://kami.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://github.com/JHUAPL/kami/releases/latest)
|
||||
[](https://repology.org/project/kami/versions)
|
||||
[](https://kami.readthedocs.io/en/latest/?badge=latest)
|
||||

|
||||
|
||||
# Kami is Agent-Based Modeling in Modern C++
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from conans import ConanFile, CMake
|
||||
|
||||
class KamiConan(ConanFile):
|
||||
name = "kami"
|
||||
version = "0.3.0"
|
||||
version = "0.4.1"
|
||||
license = "MIT"
|
||||
author = "James P. Howard, II <james.howard@jhu.edu>"
|
||||
url = "http://github.com/jhuapl/kami"
|
||||
|
||||
14
docs/changelog.rst
Normal file
14
docs/changelog.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
- :bug:`0` Cleaned up numerous issues found by CLion's linter
|
||||
- :feature:`0` Added a new overview to the documents
|
||||
- :feature:`0` Added basic installation instructions
|
||||
- :bug:`0` Retagged previous versions using pure Semantic Versioning
|
||||
- :feature:`0` Documentation for `kami::RandomScheduler`
|
||||
- :feature:`0` Added a changelog!
|
||||
|
||||
- :release:`0.3.0 <2021.09.20>`
|
||||
- :feature:`0` Initial public release.
|
||||
|
||||
.. toctree::
|
||||
@@ -43,7 +43,11 @@ extensions = [
|
||||
'sphinx.ext.githubpages',
|
||||
'breathe',
|
||||
'exhale',
|
||||
'myst_parser']
|
||||
'myst_parser',
|
||||
'releases']
|
||||
|
||||
# 'releases' (changelog) settings
|
||||
releases_github_path = "JHUAPL/kami"
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
@@ -1,34 +1,30 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. |Build (main)| image:: https://github.com/JHUAPL/kami/actions/workflows/build.yml/badge.svg?branch=main
|
||||
:target: https://github.com/JHUAPL/kami/actions/workflows/build.yml
|
||||
.. |Build (develop)| image:: https://github.com/JHUAPL/kami/actions/workflows/build.yml/badge.svg?branch=develop
|
||||
:target: https://github.com/JHUAPL/kami/actions/workflows/build.yml
|
||||
:alt: Build status (develop)
|
||||
.. |Documentation Status| image:: https://readthedocs.org/projects/kami/badge/?version=latest
|
||||
.. image:: https://github.com/JHUAPL/kami/actions/workflows/build-main.yml/badge.svg?branch=main
|
||||
:target: https://github.com/JHUAPL/kami/actions/workflows/build-main.yml
|
||||
:alt: Build Status (main)
|
||||
.. image:: https://github.com/JHUAPL/kami/actions/workflows/build-develop.yml/badge.svg?branch=develop
|
||||
:target: https://github.com/JHUAPL/kami/actions/workflows/build-develop.yml
|
||||
:alt: Build Status (develop)
|
||||
.. image:: https://readthedocs.org/projects/kami/badge/?version=latest
|
||||
:target: https://kami.readthedocs.io/en/latest/?badge=latest
|
||||
:alt: Documentation status
|
||||
.. |Release| image:: https://img.shields.io/github/release/JHUAPL/kami.svg
|
||||
:target: https://github.com/JHUAPL/spdlog/kami/latest
|
||||
:alt: Release status
|
||||
.. |ConanCenter package| image:: https://repology.org/badge/version-for-repo/conancenter/kami.svg
|
||||
:target: https://repology.org/project/kami/versions
|
||||
:alt: ConanCenter status
|
||||
:alt: Documentation Status
|
||||
.. image:: https://img.shields.io/github/release/JHUAPL/kami.svg
|
||||
:target: https://github.com/JHUAPL/kami/releases
|
||||
:alt: Release Status
|
||||
.. image:: https://img.shields.io/github/license/JHUAPL/kami
|
||||
:alt: License Information
|
||||
|
||||
Kami is 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
|
||||
extensively on the `Mesa
|
||||
<https://mesa.readthedocs.io/en/stable/overview.html>`_ library in
|
||||
Python, which itself was inspired by the `MASON
|
||||
<https://cs.gmu.edu/~eclab/projects/mason/>`_ library in Java.
|
||||
Kami is Agent-Based Modeling in Modern C++.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:hidden:
|
||||
.. toctree::
|
||||
:hidden:
|
||||
:maxdepth: 2
|
||||
|
||||
tutorial
|
||||
api/library_root
|
||||
license
|
||||
overview
|
||||
installation
|
||||
tutorial
|
||||
api/library_root
|
||||
changelog
|
||||
license
|
||||
35
docs/installation.md
Normal file
35
docs/installation.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Installation
|
||||
|
||||
## Requirements
|
||||
|
||||
The core of Kami, `libkami`, has no requirements beyond a modern C++ compiler. However, both the examples provided and
|
||||
the unit tests provided rely on three additional C++ packages:
|
||||
|
||||
* cli11/1.9.1
|
||||
* spdlog/1.8.5
|
||||
* fmt/7.1.3
|
||||
|
||||
[`CLI11`](https://cliutils.github.io/CLI11/) provides a command line interface for each of the utilities that makeup the
|
||||
examples and test suite. [`spdlog`](https://github.com/gabime/spdlog)
|
||||
provides a uniform output interface. Coupled with a command line option to set the output level, `spdlog` allows the
|
||||
unit tests and example programs to provide variable output levels depending on the users needs.
|
||||
Finally, [`fmt`](https://fmt.dev/) is required by
|
||||
`spdlog` for simple and easy string formatting.
|
||||
|
||||
## Compiling
|
||||
|
||||
To compile and test locally in kami/build:
|
||||
|
||||
git clone https://github.com/k3jph/kami.git
|
||||
cd kami
|
||||
conan install -if build .
|
||||
cmake -B build -DBUILD_SHARED_LIBS:BOOL=FALSE
|
||||
cmake --build build
|
||||
cmake --build build --target test
|
||||
|
||||
## Conan Installation (Local)
|
||||
|
||||
To install via [Conan](https://conan.io/):
|
||||
|
||||
conan create . kami/develop
|
||||
|
||||
@@ -22,4 +22,6 @@ 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.
|
||||
SOFTWARE.
|
||||
|
||||
.. toctree::
|
||||
|
||||
37
docs/overview.rst
Normal file
37
docs/overview.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
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::
|
||||
@@ -4,3 +4,5 @@ exhale
|
||||
documenteer
|
||||
myst-parser
|
||||
sphinx_bootstrap_theme
|
||||
sphinx_rtd_theme
|
||||
releases
|
||||
|
||||
@@ -23,25 +23,23 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "boltzmann1d.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/grid1d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/multigrid1d.h>
|
||||
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/stopwatch.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <CLI/Config.hpp>
|
||||
#include <CLI/Formatter.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include "boltzmann1d.h"
|
||||
|
||||
using namespace kami;
|
||||
using namespace std;
|
||||
@@ -53,14 +51,14 @@ shared_ptr<mt19937> rng = nullptr;
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<AgentID> : fmt::formatter<string> {
|
||||
auto format(AgentID agent_id, format_context &ctx) {
|
||||
[[maybe_unused]] static auto format(AgentID agent_id, format_context &ctx) {
|
||||
return format_to(ctx.out(), "{}", agent_id.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<GridCoord1D> : fmt::formatter<string> {
|
||||
auto format(GridCoord1D coord, format_context &ctx) {
|
||||
[[maybe_unused]] static auto format(const GridCoord1D& coord, format_context &ctx) {
|
||||
return format_to(ctx.out(), "{}", coord.to_string());
|
||||
}
|
||||
};
|
||||
@@ -82,7 +80,7 @@ void MoneyAgent1D::move_agent() {
|
||||
console->trace("Entering move_agent");
|
||||
auto agent_id = get_agent_id();
|
||||
auto move_list = _world->get_neighborhood(agent_id, false);
|
||||
std::uniform_int_distribution<int> dist(0, move_list.size() - 1);
|
||||
std::uniform_int_distribution<int> dist(0, (int)move_list.size() - 1);
|
||||
auto new_location = move_list[dist(*rng)];
|
||||
|
||||
console->trace("Moving Agent {} to location {}", agent_id, new_location);
|
||||
@@ -90,29 +88,23 @@ void MoneyAgent1D::move_agent() {
|
||||
console->trace("Exiting move_agent");
|
||||
}
|
||||
|
||||
int MoneyAgent1D::get_wealth() { return _agent_wealth; }
|
||||
|
||||
void MoneyAgent1D::set_wealth(int wealth) { _agent_wealth = wealth; }
|
||||
|
||||
void MoneyAgent1D::give_money() {
|
||||
AgentID agent_id = get_agent_id();
|
||||
GridCoord1D location = _world->get_location_by_agent(agent_id);
|
||||
vector<AgentID> *cell_mates = _world->get_location_contents(location);
|
||||
|
||||
if (cell_mates->size() > 1) {
|
||||
std::uniform_int_distribution<int> dist(0, cell_mates->size() - 1);
|
||||
std::uniform_int_distribution<int> dist(0, (int)cell_mates->size() - 1);
|
||||
AgentID other_agent_id = cell_mates->at(dist(*rng));
|
||||
auto other_agent = _model->get_agent_by_id(other_agent_id);
|
||||
|
||||
console->trace("Agent {} giving unit of wealth to agent {}", agent_id,
|
||||
other_agent_id);
|
||||
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
|
||||
other_agent->_agent_wealth += 1;
|
||||
_agent_wealth -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents,
|
||||
unsigned int length_x) {
|
||||
BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents, unsigned int length_x) {
|
||||
_world = new MultiGrid1D(length_x, true);
|
||||
_sched = new RandomScheduler(this, rng);
|
||||
|
||||
@@ -120,23 +112,20 @@ BoltzmannWealthModel1D::BoltzmannWealthModel1D(unsigned int number_agents,
|
||||
MoneyAgent1D::set_world(_world);
|
||||
MoneyAgent1D::set_model(this);
|
||||
|
||||
std::uniform_int_distribution<int> dist(0, length_x - 1);
|
||||
std::uniform_int_distribution<int> dist(0, (int)length_x - 1);
|
||||
|
||||
for (unsigned int i = 0; i < number_agents; i++) {
|
||||
MoneyAgent1D *new_agent = new MoneyAgent1D();
|
||||
auto *new_agent = new MoneyAgent1D();
|
||||
|
||||
_agent_list.insert(pair<AgentID, MoneyAgent1D *>(
|
||||
new_agent->get_agent_id(), new_agent));
|
||||
_agent_list.insert(pair<AgentID, MoneyAgent1D *>(new_agent->get_agent_id(), new_agent));
|
||||
_sched->add_agent(new_agent->get_agent_id());
|
||||
_world->add_agent(new_agent->get_agent_id(), GridCoord1D(dist(*rng)));
|
||||
}
|
||||
}
|
||||
|
||||
BoltzmannWealthModel1D::~BoltzmannWealthModel1D() {
|
||||
for (auto agent_pair = _agent_list.begin(); agent_pair != _agent_list.end();
|
||||
agent_pair++) {
|
||||
delete agent_pair->second;
|
||||
}
|
||||
for (auto & agent_pair : _agent_list)
|
||||
delete agent_pair.second;
|
||||
|
||||
delete _sched;
|
||||
delete _world;
|
||||
@@ -161,29 +150,19 @@ int main(int argc, char **argv) {
|
||||
string ident = "boltzmann1d";
|
||||
CLI::App app{ident};
|
||||
string log_level_option = "info";
|
||||
unsigned int x_size = 16, agent_count = x_size, max_steps = 100,
|
||||
initial_seed = 42;
|
||||
unsigned int x_size = 16, agent_count = x_size, max_steps = 100, initial_seed = 42;
|
||||
|
||||
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("-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 colums")
|
||||
->check(CLI::PositiveNumber);
|
||||
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("-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);
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
console = spdlog::stdout_color_st(ident);
|
||||
console->set_level(spdlog::level::from_str(log_level_option));
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING,
|
||||
log_level_option);
|
||||
console->info(
|
||||
"Starting Boltzmann Wealth Model with {} agents on a {}-unit grid for "
|
||||
"{} steps",
|
||||
agent_count, x_size, max_steps);
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, log_level_option);
|
||||
console->info("Starting Boltzmann Wealth Model with {} agents on a {}-unit grid for {} steps",agent_count, x_size, max_steps);
|
||||
|
||||
rng = make_shared<mt19937>(initial_seed);
|
||||
BoltzmannWealthModel1D model(agent_count, x_size);
|
||||
@@ -193,6 +172,5 @@ int main(int argc, char **argv) {
|
||||
console->trace("Initiating model step {}", i);
|
||||
model.step();
|
||||
}
|
||||
console->info(
|
||||
"Boltzman Wealth Model simulation complete, requiring {} seconds", sw);
|
||||
console->info("Boltzmann Wealth Model simulation complete, requiring {} seconds", sw);
|
||||
}
|
||||
|
||||
@@ -24,17 +24,16 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef BOLTZMAN1D_H
|
||||
#define BOLTZMAN1D_H
|
||||
#ifndef BOLTZMANN1D_H
|
||||
#define BOLTZMANN1D_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/multigrid1d.h>
|
||||
#include <kami/random.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
using namespace kami;
|
||||
using namespace std;
|
||||
@@ -43,7 +42,7 @@ using namespace std;
|
||||
* A sample agent for a one-dimensional Boltzmann wealth model
|
||||
*/
|
||||
class MoneyAgent1D : public Agent {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Create the agent
|
||||
*/
|
||||
@@ -52,7 +51,7 @@ class MoneyAgent1D : public Agent {
|
||||
/**
|
||||
* Execute a single time-step for the agent
|
||||
*/
|
||||
void step();
|
||||
void step() override;
|
||||
|
||||
/**
|
||||
* Give the agent a reference copy of the domain it is expected to work in
|
||||
@@ -69,22 +68,12 @@ class MoneyAgent1D : public Agent {
|
||||
*/
|
||||
void move_agent();
|
||||
|
||||
/**
|
||||
* Return the wealth of the agent
|
||||
*/
|
||||
int get_wealth();
|
||||
|
||||
/**
|
||||
* Set the wealth of the agent
|
||||
*/
|
||||
void set_wealth(int wealth);
|
||||
|
||||
/**
|
||||
* Give money to a random agent
|
||||
*/
|
||||
void give_money();
|
||||
|
||||
private:
|
||||
private:
|
||||
static MultiGrid1D *_world;
|
||||
static BoltzmannWealthModel1D *_model;
|
||||
int _step_counter;
|
||||
@@ -95,16 +84,15 @@ class MoneyAgent1D : public Agent {
|
||||
* The one-dimensional Boltzmann wealth model
|
||||
*/
|
||||
class BoltzmannWealthModel1D : public Model {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Create an instance of the one-dimensional Boltzman wealth model.
|
||||
* Create an instance of the one-dimensional Boltzmann wealth model.
|
||||
*
|
||||
* @param[in] number_agents the number of agents to assign to the model.
|
||||
* @param[in] length_x the length of the one-dimensional world the agents
|
||||
* occupy.
|
||||
*/
|
||||
BoltzmannWealthModel1D(unsigned int number_agents = 10,
|
||||
unsigned int length_x = 10);
|
||||
explicit BoltzmannWealthModel1D(unsigned int number_agents = 10, unsigned int length_x = 10);
|
||||
|
||||
/**
|
||||
* Destroy the instance
|
||||
@@ -114,27 +102,27 @@ class BoltzmannWealthModel1D : public Model {
|
||||
/**
|
||||
* Execute a single time-step for the model.
|
||||
*/
|
||||
void step();
|
||||
void step() override;
|
||||
|
||||
/**
|
||||
* Execute a number of time-steps for the model.
|
||||
*
|
||||
*
|
||||
* @param[in] n the number of steps to execute.
|
||||
*/
|
||||
void run(unsigned int n);
|
||||
void run(unsigned int n) override;
|
||||
|
||||
/**
|
||||
* Get the MoneyAgent instance associated with the given `AgentID`
|
||||
*
|
||||
*
|
||||
* @returns an pointer to the `MoneyAgent` that was requested.
|
||||
*/
|
||||
MoneyAgent1D *get_agent_by_id(AgentID agent_id) const;
|
||||
[[nodiscard]] MoneyAgent1D *get_agent_by_id(AgentID agent_id) const override;
|
||||
|
||||
private:
|
||||
private:
|
||||
map<AgentID, MoneyAgent1D *> _agent_list;
|
||||
RandomScheduler *_sched;
|
||||
MultiGrid1D *_world;
|
||||
unsigned int _step_count;
|
||||
};
|
||||
|
||||
#endif // BOLTZMAN1D_H
|
||||
#endif // BOLTZMANN1D_H
|
||||
|
||||
@@ -23,23 +23,21 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/grid2d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/multigrid1d.h>
|
||||
#include <kami/multigrid2d.h>
|
||||
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/stopwatch.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <CLI/Config.hpp>
|
||||
#include <CLI/Formatter.hpp>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
#include "boltzmann2d.h"
|
||||
|
||||
@@ -53,14 +51,14 @@ shared_ptr<mt19937> rng = nullptr;
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<AgentID> : fmt::formatter<string> {
|
||||
auto format(AgentID agent_id, format_context &ctx) {
|
||||
[[maybe_unused]] static auto format(AgentID agent_id, format_context &ctx) {
|
||||
return format_to(ctx.out(), "{}", agent_id.to_string());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt::formatter<GridCoord2D> : fmt::formatter<string> {
|
||||
auto format(GridCoord2D coord, format_context &ctx) {
|
||||
[[maybe_unused]] static auto format(const GridCoord2D& coord, format_context &ctx) {
|
||||
return format_to(ctx.out(), "{}", coord.to_string());
|
||||
}
|
||||
};
|
||||
@@ -82,7 +80,7 @@ void MoneyAgent2D::move_agent() {
|
||||
console->trace("Entering move_agent");
|
||||
auto agent_id = get_agent_id();
|
||||
auto move_list = _world->get_neighborhood(agent_id, GridNeighborhoodType::Moore, false);
|
||||
std::uniform_int_distribution<int> dist(0, move_list.size() - 1);
|
||||
std::uniform_int_distribution<int> dist(0, (int) move_list.size() - 1);
|
||||
auto new_location = move_list[dist(*rng)];
|
||||
|
||||
console->trace("Moving Agent {} to location {}", agent_id, new_location);
|
||||
@@ -90,31 +88,23 @@ void MoneyAgent2D::move_agent() {
|
||||
console->trace("Exiting move_agent");
|
||||
}
|
||||
|
||||
int MoneyAgent2D::get_wealth() { return _agent_wealth; }
|
||||
|
||||
void MoneyAgent2D::set_wealth(int newWealth) { _agent_wealth = newWealth; }
|
||||
|
||||
void MoneyAgent2D::give_money() {
|
||||
AgentID agent_id = get_agent_id();
|
||||
GridCoord2D location = _world->get_location_by_agent(agent_id);
|
||||
vector<AgentID> *cell_mates = _world->get_location_contents(location);
|
||||
|
||||
if (cell_mates->size() > 1) {
|
||||
std::uniform_int_distribution<int> dist(0, cell_mates->size() - 1);
|
||||
std::uniform_int_distribution<int> dist(0, (int)cell_mates->size() - 1);
|
||||
AgentID other_agent_id = cell_mates->at(dist(*rng));
|
||||
auto other_agent = _model->get_agent_by_id(other_agent_id);
|
||||
|
||||
console->trace("Agent {} giving unit of wealth to agent {}", agent_id,
|
||||
other_agent_id);
|
||||
console->trace("Agent {} giving unit of wealth to agent {}", agent_id, other_agent_id);
|
||||
other_agent->_agent_wealth += 1;
|
||||
_agent_wealth -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents,
|
||||
unsigned int length_x,
|
||||
unsigned int length_y,
|
||||
unsigned int new_seed) {
|
||||
BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents, unsigned int length_x, unsigned int length_y, unsigned int new_seed) {
|
||||
rng = make_shared<mt19937>();
|
||||
rng->seed(new_seed);
|
||||
|
||||
@@ -127,25 +117,21 @@ BoltzmannWealthModel2D::BoltzmannWealthModel2D(unsigned int number_agents,
|
||||
MoneyAgent2D::set_world(_world);
|
||||
MoneyAgent2D::set_model(this);
|
||||
|
||||
std::uniform_int_distribution<int> dist_x(0, length_x - 1);
|
||||
std::uniform_int_distribution<int> dist_y(0, length_y - 1);
|
||||
std::uniform_int_distribution<int> dist_x(0, (int)length_x - 1);
|
||||
std::uniform_int_distribution<int> dist_y(0, (int)length_y - 1);
|
||||
|
||||
for (unsigned int i = 0; i < number_agents; i++) {
|
||||
MoneyAgent2D *new_agent = new MoneyAgent2D();
|
||||
auto *new_agent = new MoneyAgent2D();
|
||||
|
||||
_agent_list.insert(pair<AgentID, MoneyAgent2D *>(
|
||||
new_agent->get_agent_id(), new_agent));
|
||||
_agent_list.insert(pair<AgentID, MoneyAgent2D *>(new_agent->get_agent_id(), new_agent));
|
||||
_sched->add_agent(new_agent->get_agent_id());
|
||||
_world->add_agent(new_agent->get_agent_id(),
|
||||
GridCoord2D(dist_x(*rng), dist_x(*rng)));
|
||||
_world->add_agent(new_agent->get_agent_id(), GridCoord2D(dist_x(*rng), dist_x(*rng)));
|
||||
}
|
||||
}
|
||||
|
||||
BoltzmannWealthModel2D::~BoltzmannWealthModel2D() {
|
||||
for (auto agent_pair = _agent_list.begin(); agent_pair != _agent_list.end();
|
||||
agent_pair++) {
|
||||
delete agent_pair->second;
|
||||
}
|
||||
for (auto & agent_pair : _agent_list)
|
||||
delete agent_pair.second;
|
||||
|
||||
delete _sched;
|
||||
delete _world;
|
||||
@@ -169,31 +155,20 @@ int main(int argc, char **argv) {
|
||||
std::string ident = "boltzmann2d";
|
||||
CLI::App app{ident};
|
||||
string log_level_option = "info";
|
||||
unsigned int x_size = 16, y_size = 16, agent_count = x_size * y_size,
|
||||
max_steps = 100, initial_seed = 42;
|
||||
unsigned int x_size = 16, y_size = 16, agent_count = x_size * y_size, max_steps = 100, initial_seed = 42;
|
||||
|
||||
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("-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 colums")
|
||||
->check(CLI::PositiveNumber);
|
||||
app.add_option("-y", y_size, "Set the number of rows")
|
||||
->check(CLI::PositiveNumber);
|
||||
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("-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);
|
||||
app.add_option("-y", y_size, "Set the number of rows")->check(CLI::PositiveNumber);
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
console = spdlog::stdout_color_st(ident);
|
||||
console->set_level(spdlog::level::from_str(log_level_option));
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING,
|
||||
log_level_option);
|
||||
console->info(
|
||||
"Starting Boltzmann Wealth Model with {} agents on a {}x{}-unit grid "
|
||||
"for {} steps",
|
||||
agent_count, x_size, y_size, max_steps);
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, log_level_option);
|
||||
console->info("Starting Boltzmann Wealth Model with {} agents on a {}x{}-unit grid for {} steps", agent_count, x_size, y_size, max_steps);
|
||||
|
||||
BoltzmannWealthModel2D model(agent_count, x_size, y_size, initial_seed);
|
||||
|
||||
@@ -202,6 +177,5 @@ int main(int argc, char **argv) {
|
||||
console->trace("Initiating model step {}", i);
|
||||
model.step();
|
||||
}
|
||||
console->info(
|
||||
"Boltzman Wealth Model simulation complete, requiring {} seconds", sw);
|
||||
console->info("Boltzmann Wealth Model simulation complete, requiring {} seconds", sw);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef BOLTZMAN2D_H
|
||||
#define BOLTZMAN2D_H
|
||||
#ifndef BOLTZMANN2D_H
|
||||
#define BOLTZMANN2D_H
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/kami.h>
|
||||
@@ -42,7 +42,7 @@ using namespace std;
|
||||
* A sample agent for a two-dimensional Boltzmann wealth model
|
||||
*/
|
||||
class MoneyAgent2D : public Agent {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Create the agent
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ class MoneyAgent2D : public Agent {
|
||||
/**
|
||||
* Execute a single time-step for the agent
|
||||
*/
|
||||
void step();
|
||||
void step() override;
|
||||
|
||||
/**
|
||||
* Give the agent a reference copy of the domain it is expected to work in
|
||||
@@ -68,22 +68,12 @@ class MoneyAgent2D : public Agent {
|
||||
*/
|
||||
void move_agent();
|
||||
|
||||
/**
|
||||
* Return the wealth of the agent
|
||||
*/
|
||||
int get_wealth();
|
||||
|
||||
/**
|
||||
* Set the wealth of the agent
|
||||
*/
|
||||
void set_wealth(int wealth);
|
||||
|
||||
/**
|
||||
* Give money to a random agent
|
||||
*/
|
||||
void give_money();
|
||||
|
||||
private:
|
||||
private:
|
||||
static MultiGrid2D *_world;
|
||||
static BoltzmannWealthModel2D *_model;
|
||||
int _step_counter;
|
||||
@@ -94,9 +84,9 @@ class MoneyAgent2D : public Agent {
|
||||
* The two-dimensional Boltzmann wealth model
|
||||
*/
|
||||
class BoltzmannWealthModel2D : public Model {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* Create an instance of the two-dimensional Boltzman wealth model.
|
||||
* Create an instance of the two-dimensional Boltzmann wealth model.
|
||||
*
|
||||
* @param[in] number_agents the number of agents to assign to the model.
|
||||
* @param[in] length_x the length of the two-dimensional world the agents
|
||||
@@ -106,10 +96,7 @@ class BoltzmannWealthModel2D : public Model {
|
||||
* @param[in] new_seed the initial seed used for the random number
|
||||
* generator.
|
||||
*/
|
||||
BoltzmannWealthModel2D(unsigned int number_agents = 10,
|
||||
unsigned int length_x = 10,
|
||||
unsigned int length_y = 10,
|
||||
unsigned int new_seed = 42);
|
||||
explicit BoltzmannWealthModel2D(unsigned int number_agents = 10, unsigned int length_x = 10, unsigned int length_y = 10, unsigned int new_seed = 42);
|
||||
|
||||
/**
|
||||
* Destroy the instance
|
||||
@@ -119,32 +106,27 @@ class BoltzmannWealthModel2D : public Model {
|
||||
/**
|
||||
* Execute a single time-step for the model.
|
||||
*/
|
||||
void step();
|
||||
void step() override;
|
||||
|
||||
/**
|
||||
* Execute a number of time-steps for the model.
|
||||
*
|
||||
* @param[in] n the number of steps to execute.
|
||||
*/
|
||||
void run(unsigned int n);
|
||||
|
||||
/**
|
||||
* Return the seed used to initialize the model.
|
||||
*/
|
||||
int get_seed() const;
|
||||
void run(unsigned int n) override;
|
||||
|
||||
/**
|
||||
* Get the MoneyAgent2D instance associated with the given `AgentID`
|
||||
*
|
||||
* @returns an pointer to the `MoneyAgent2D` that was requested.
|
||||
*/
|
||||
MoneyAgent2D *get_agent_by_id(AgentID agent_id) const;
|
||||
[[nodiscard]] MoneyAgent2D *get_agent_by_id(AgentID agent_id) const override;
|
||||
|
||||
private:
|
||||
private:
|
||||
map<AgentID, MoneyAgent2D *> _agent_list;
|
||||
RandomScheduler *_sched;
|
||||
MultiGrid2D *_world;
|
||||
unsigned int _step_count;
|
||||
};
|
||||
|
||||
#endif // BOLTZMAN2D_H
|
||||
#endif // BOLTZMANN2D_H
|
||||
|
||||
@@ -27,11 +27,12 @@
|
||||
#ifndef KAMI_AGENT_H
|
||||
#define KAMI_AGENT_H
|
||||
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <kami/kami.h>
|
||||
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
@@ -43,77 +44,77 @@ namespace kami {
|
||||
*
|
||||
* @see Agent
|
||||
*/
|
||||
class LIBKAMI_EXPORT AgentID {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new unique identifier.
|
||||
*/
|
||||
AgentID() : _id(_id_next++){};
|
||||
class LIBKAMI_EXPORT AgentID {
|
||||
public:
|
||||
/**
|
||||
* Constructs a new unique identifier.
|
||||
*/
|
||||
AgentID() : _id(_id_next++){};
|
||||
|
||||
/**
|
||||
* Convert the identifier to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `AgentID` as `std::string`.
|
||||
*/
|
||||
std::string to_string() const { return std::to_string(_id); }
|
||||
/**
|
||||
* Convert the identifier to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `AgentID` as `std::string`.
|
||||
*/
|
||||
[[nodiscard]] std::string to_string() const { return std::to_string(_id); }
|
||||
|
||||
/**
|
||||
* Test if two `AgentID` instances are equal.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are equal and false if not.
|
||||
*/
|
||||
friend bool operator==(const AgentID &lhs, const AgentID &rhs);
|
||||
/**
|
||||
* Test if two `AgentID` instances are equal.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are equal and false if not.
|
||||
*/
|
||||
friend bool operator==(const AgentID &lhs, const AgentID &rhs);
|
||||
|
||||
/**
|
||||
* Test if two `AgentID` instances are not equal.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are not equal and false if they are.
|
||||
*/
|
||||
friend bool operator!=(const AgentID &lhs, const AgentID &rhs);
|
||||
/**
|
||||
* Test if two `AgentID` instances are not equal.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are not equal and false if they are.
|
||||
*/
|
||||
friend bool operator!=(const AgentID &lhs, const AgentID &rhs);
|
||||
|
||||
/**
|
||||
* Test if one AgentID is less than another.
|
||||
*
|
||||
* Due to the way AgentID instances are used internally,
|
||||
* the AgentID must be orderable. The `<` operator provides a
|
||||
* basic ordering sufficient for `std::map`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the ordering test.
|
||||
* @param rhs is the right-hand side of the ordering test.
|
||||
* @return true if `lhs` is "less than" `rhs` as determined by the
|
||||
* underlying implementation of the `AgentID`.
|
||||
*/
|
||||
friend bool operator<(const AgentID &lhs, const AgentID &rhs);
|
||||
/**
|
||||
* Test if one AgentID is less than another.
|
||||
*
|
||||
* Due to the way AgentID instances are used internally,
|
||||
* the AgentID must be orderable. The `<` operator provides a
|
||||
* basic ordering sufficient for `std::map`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the ordering test.
|
||||
* @param rhs is the right-hand side of the ordering test.
|
||||
* @return true if `lhs` is "less than" `rhs` as determined by the
|
||||
* underlying implementation of the `AgentID`.
|
||||
*/
|
||||
friend bool operator<(const AgentID &lhs, const AgentID &rhs);
|
||||
|
||||
/**
|
||||
* Output an AgentID to the specified output stream
|
||||
*
|
||||
* The form of the output will be the same as that produced by the
|
||||
* `to_string()` member function.
|
||||
*
|
||||
* @param lhs is the stream to output the `AgentID` to
|
||||
* @param rhs is the `AgentID` to output
|
||||
* @return the output stream for reuse
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs);
|
||||
/**
|
||||
* Output an AgentID to the specified output stream
|
||||
*
|
||||
* The form of the output will be the same as that produced by the
|
||||
* `to_string()` member function.
|
||||
*
|
||||
* @param lhs is the stream to output the `AgentID` to
|
||||
* @param rhs is the `AgentID` to output
|
||||
* @return the output stream for reuse
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs);
|
||||
|
||||
private:
|
||||
inline static long long _id_next = 1;
|
||||
private:
|
||||
inline static long long _id_next = 1;
|
||||
|
||||
/**
|
||||
* The unique identifier is a `long long`.
|
||||
*
|
||||
* The unique identifier is an unsigned integer that increments
|
||||
* monotonically with each new `AgentID` instantiated. This is
|
||||
* substantially faster than other potential identifiers, such
|
||||
* as MD5 hashes or UUID objects.
|
||||
*/
|
||||
long long _id;
|
||||
};
|
||||
/**
|
||||
* The unique identifier is a `long long`.
|
||||
*
|
||||
* The unique identifier is an unsigned integer that increments
|
||||
* monotonically with each new `AgentID` instantiated. This is
|
||||
* substantially faster than other potential identifiers, such
|
||||
* as MD5 hashes or UUID objects.
|
||||
*/
|
||||
long long _id;
|
||||
};
|
||||
|
||||
/**
|
||||
* A superclass for all agents.
|
||||
@@ -124,58 +125,58 @@ class LIBKAMI_EXPORT AgentID {
|
||||
*
|
||||
* @see `StagedAgent`
|
||||
*/
|
||||
class LIBKAMI_EXPORT Agent {
|
||||
public:
|
||||
/**
|
||||
* Get the `Agent`'s `AgentID`.
|
||||
*
|
||||
* @return the `AgentID`
|
||||
*/
|
||||
AgentID get_agent_id() const;
|
||||
class LIBKAMI_EXPORT Agent {
|
||||
public:
|
||||
/**
|
||||
* Get the `Agent`'s `AgentID`.
|
||||
*
|
||||
* @return the `AgentID`
|
||||
*/
|
||||
[[nodiscard]] AgentID get_agent_id() const;
|
||||
|
||||
/**
|
||||
* Execute a time-step for the agent
|
||||
*
|
||||
* This function should step the agent instance. Any activities that the
|
||||
* agent should perform as part of its time step should be in this function.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
/**
|
||||
* Execute a time-step for the agent
|
||||
*
|
||||
* This function should step the agent instance. Any activities that the
|
||||
* agent should perform as part of its time step should be in this function.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
|
||||
/**
|
||||
* Compare if two `Agent`s are the same `Agent`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are equal and false if not.
|
||||
*
|
||||
* @note This does not compare that two Agent instances are
|
||||
* identical. Accordingly, this can be used to compare two instances
|
||||
* of the same Agent at different points in its time stream.
|
||||
*
|
||||
* Subclasses of Agent may chose to extend this operator to tighten
|
||||
* the restrictioons on the comparison.
|
||||
*/
|
||||
friend bool operator==(const Agent &lhs, const Agent &rhs);
|
||||
/**
|
||||
* Compare if two `Agent`s are the same `Agent`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are equal and false if not.
|
||||
*
|
||||
* @note This does not compare that two Agent instances are
|
||||
* identical. Accordingly, this can be used to compare two instances
|
||||
* of the same Agent at different points in its time stream.
|
||||
*
|
||||
* Subclasses of Agent may chose to extend this operator to tighten
|
||||
* the restrictions on the comparison.
|
||||
*/
|
||||
friend bool operator==(const Agent &lhs, const Agent &rhs);
|
||||
|
||||
/**
|
||||
* Compare if two `Agent`s are not the same `Agent`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are not equal and false if they are.
|
||||
*
|
||||
* @note This does not compare that two Agent instances are
|
||||
* identical. Accordingly, this can be used to compare two instances
|
||||
* of the same `Agent` at different points in its time stream.
|
||||
*
|
||||
* Subclasses of `Agent` may chose to extend this operator to tighten
|
||||
* the restrictioons on the comparison.
|
||||
*/
|
||||
friend bool operator!=(const Agent &lhs, const Agent &rhs);
|
||||
/**
|
||||
* Compare if two `Agent`s are not the same `Agent`.
|
||||
*
|
||||
* @param lhs is the left-hand side of the equality test.
|
||||
* @param rhs is the right-hand side of the equality test.
|
||||
* @return true is they are not equal and false if they are.
|
||||
*
|
||||
* @note This does not compare that two Agent instances are
|
||||
* identical. Accordingly, this can be used to compare two instances
|
||||
* of the same `Agent` at different points in its time stream.
|
||||
*
|
||||
* Subclasses of `Agent` may chose to extend this operator to tighten
|
||||
* the restrictions on the comparison.
|
||||
*/
|
||||
friend bool operator!=(const Agent &lhs, const Agent &rhs);
|
||||
|
||||
private:
|
||||
const AgentID _agent_id;
|
||||
};
|
||||
private:
|
||||
const AgentID _agent_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* A superclass for all staged agents.
|
||||
@@ -189,17 +190,17 @@ class LIBKAMI_EXPORT Agent {
|
||||
*
|
||||
* `StagedAgents` must implement both the `step()` and `advance()` functions.
|
||||
*/
|
||||
class LIBKAMI_EXPORT StagedAgent : public Agent {
|
||||
public:
|
||||
/**
|
||||
* Post-step advance the agent
|
||||
*
|
||||
* This method should be called after `step()`. Any updates or cleanups to
|
||||
* the agent that must happen for the `StagedAgent` to complete its step must
|
||||
* happen here.
|
||||
*/
|
||||
virtual void advance() = 0;
|
||||
};
|
||||
class LIBKAMI_EXPORT StagedAgent : public Agent {
|
||||
public:
|
||||
/**
|
||||
* Post-step advance the agent
|
||||
*
|
||||
* This method should be called after `step()`. Any updates or cleanups to
|
||||
* the agent that must happen for the `StagedAgent` to complete its step must
|
||||
* happen here.
|
||||
*/
|
||||
virtual void advance() = 0;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
#ifndef KAMI_DOMAIN_H
|
||||
#define KAMI_DOMAIN_H
|
||||
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <kami/kami.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
@@ -38,7 +38,7 @@ namespace kami {
|
||||
*
|
||||
* Implementations of virtual environments are expected to subclass `Domain`.
|
||||
*/
|
||||
class LIBKAMI_EXPORT Domain {};
|
||||
class LIBKAMI_EXPORT Domain {};
|
||||
|
||||
/**
|
||||
* Provides a coordinate system for each `Domain`.
|
||||
@@ -52,27 +52,27 @@ class LIBKAMI_EXPORT Domain {};
|
||||
*
|
||||
* @see GridCoord
|
||||
*/
|
||||
class LIBKAMI_EXPORT Coord {
|
||||
public:
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
virtual std::string to_string() const = 0;
|
||||
class LIBKAMI_EXPORT Coord {
|
||||
public:
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
[[nodiscard]] virtual std::string to_string() const = 0;
|
||||
|
||||
/**
|
||||
* Output a `Coord` to the specified output stream
|
||||
*
|
||||
* The form of the output will be the same as that produced by the
|
||||
* `to_string()` member function.
|
||||
*
|
||||
* @param lhs is the stream to output the `Coord` to
|
||||
* @param rhs is the `Coord` to output
|
||||
* @return the output stream for reuse
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const Coord &rhs);
|
||||
};
|
||||
/**
|
||||
* Output a `Coord` to the specified output stream
|
||||
*
|
||||
* The form of the output will be the same as that produced by the
|
||||
* `to_string()` member function.
|
||||
*
|
||||
* @param lhs is the stream to output the `Coord` to
|
||||
* @param rhs is the `Coord` to output
|
||||
* @return the output stream for reuse
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const Coord &rhs);
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -27,11 +27,11 @@
|
||||
#ifndef KAMI_GRID_H
|
||||
#define KAMI_GRID_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <kami/domain.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
@@ -42,47 +42,47 @@ namespace kami {
|
||||
* distinction between those neighborhoods that include those cells touching on
|
||||
* the corners or diagonally and those neighborhoods that do not.
|
||||
*/
|
||||
enum class GridNeighborhoodType {
|
||||
/**
|
||||
* @brief Moore neighborhood
|
||||
*
|
||||
* @details Moore neighborhood types include diagonally-adjacent cells as
|
||||
* neighbors.
|
||||
*/
|
||||
Moore,
|
||||
enum class GridNeighborhoodType {
|
||||
/**
|
||||
* @brief Moore neighborhood
|
||||
*
|
||||
* @details Moore neighborhood types include diagonally-adjacent cells as
|
||||
* neighbors.
|
||||
*/
|
||||
Moore [[maybe_unused]],
|
||||
|
||||
/**
|
||||
* @brief Von Neumann neighborhood
|
||||
*
|
||||
* @details Von Neumann neighborhood types do not include
|
||||
* diagonally-adjacent cells as neighbors.
|
||||
*/
|
||||
VonNeumann
|
||||
};
|
||||
/**
|
||||
* @brief Von Neumann neighborhood
|
||||
*
|
||||
* @details Von Neumann neighborhood types do not include
|
||||
* diagonally-adjacent cells as neighbors.
|
||||
*/
|
||||
VonNeumann [[maybe_unused]]
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Distance types for orthogonal grid domains
|
||||
*/
|
||||
enum class GridDistanceType {
|
||||
/**
|
||||
* @brief Euclidean distance.
|
||||
*
|
||||
* @details The Euclidean distance is the length of the line segment
|
||||
* connecting two points. This is commonly called a "beeline" or
|
||||
* "as the crow flies."
|
||||
*/
|
||||
Euclidean,
|
||||
enum class GridDistanceType {
|
||||
/**
|
||||
* @brief Euclidean distance.
|
||||
*
|
||||
* @details The Euclidean distance is the length of the line segment
|
||||
* connecting two points. This is commonly called a "beeline" or
|
||||
* "as the crow flies."
|
||||
*/
|
||||
Euclidean [[maybe_unused]],
|
||||
|
||||
/**
|
||||
* @brief Manhattan distance.
|
||||
*
|
||||
* @details The Manhattan distance is the sum of the absolute value of the
|
||||
* differences of the elements. This is commonly called the
|
||||
* "taxicab distance," "rectilinear distance," or many other [formal
|
||||
* names](https://en.wikipedia.org/wiki/Taxicab_geometry).
|
||||
*/
|
||||
Manhattan
|
||||
};
|
||||
/**
|
||||
* @brief Manhattan distance.
|
||||
*
|
||||
* @details The Manhattan distance is the sum of the absolute value of the
|
||||
* differences of the elements. This is commonly called the
|
||||
* "taxicab distance," "rectilinear distance," or many other [formal
|
||||
* names](https://en.wikipedia.org/wiki/Taxicab_geometry).
|
||||
*/
|
||||
Manhattan [[maybe_unused]]
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstract domain based on a gridded environment.
|
||||
@@ -91,15 +91,15 @@ enum class GridDistanceType {
|
||||
* rectilinear grid where the cells are equal size and laid out in an ordered
|
||||
* fashion.
|
||||
*/
|
||||
class LIBKAMI_EXPORT GridDomain : public Domain {};
|
||||
class LIBKAMI_EXPORT GridDomain : public Domain {};
|
||||
|
||||
/**
|
||||
* @brief An abstract for gridded coordinates.
|
||||
*
|
||||
* @details All gridded coordinates are expected to subclass `GridCoord`.
|
||||
*/
|
||||
class LIBKAMI_EXPORT GridCoord : public Coord {};
|
||||
class LIBKAMI_EXPORT GridCoord : public Coord {};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
#endif // KAMI_DOMAIN_H
|
||||
#endif // KAMI_GRID_H
|
||||
|
||||
@@ -27,223 +27,221 @@
|
||||
#ifndef KAMI_GRID1D_H
|
||||
#define KAMI_GRID1D_H
|
||||
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
* One-dimensional coordinates
|
||||
*/
|
||||
class LIBKAMI_EXPORT GridCoord1D : public GridCoord {
|
||||
public:
|
||||
/**
|
||||
* Constructor for one-dimensional coordinates
|
||||
*/
|
||||
GridCoord1D(int x_coord) : _x_coord(x_coord){};
|
||||
class LIBKAMI_EXPORT GridCoord1D : public GridCoord {
|
||||
public:
|
||||
/**
|
||||
* Constructor for one-dimensional coordinates
|
||||
*/
|
||||
explicit GridCoord1D(int x_coord) : _x_coord(x_coord){};
|
||||
|
||||
/**
|
||||
* Return the `x` coordinate
|
||||
*/
|
||||
int get_x_location(void) const;
|
||||
/**
|
||||
* Return the `x` coordinate
|
||||
*/
|
||||
[[nodiscard]] int get_x_location() const;
|
||||
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
std::string to_string() const;
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
[[nodiscard]] std::string to_string() const override;
|
||||
|
||||
/**
|
||||
* Test if two coordinates are equal
|
||||
*/
|
||||
friend bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs);
|
||||
/**
|
||||
* Test if two coordinates are equal
|
||||
*/
|
||||
friend bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs);
|
||||
|
||||
/**
|
||||
* Test if two coordinates are not equal
|
||||
*/
|
||||
friend bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs);
|
||||
/**
|
||||
* Test if two coordinates are not equal
|
||||
*/
|
||||
friend bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs);
|
||||
|
||||
/**
|
||||
* Output a given coordinate to the specified stream
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs);
|
||||
/**
|
||||
* Output a given coordinate to the specified stream
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs);
|
||||
|
||||
private:
|
||||
int _x_coord;
|
||||
};
|
||||
private:
|
||||
int _x_coord;
|
||||
};
|
||||
|
||||
/**
|
||||
* A one-dimensional grid where each cell may contain agents
|
||||
*
|
||||
* The grid is linear and may wrap around in its only dimension.
|
||||
*
|
||||
*
|
||||
* @see `MultiGrid1D`
|
||||
* @see `SoloGrid1D`
|
||||
*/
|
||||
class LIBKAMI_EXPORT Grid1D : public GridDomain {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
Grid1D(unsigned int maximum_x, bool wrap_x = false);
|
||||
class LIBKAMI_EXPORT Grid1D : public GridDomain {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
explicit Grid1D(unsigned int maximum_x, bool wrap_x = false);
|
||||
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
virtual ~Grid1D();
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
virtual ~Grid1D();
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true.
|
||||
*/
|
||||
virtual bool add_agent(AgentID agent_id, GridCoord1D coord) = 0;
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true.
|
||||
*/
|
||||
virtual bool add_agent(AgentID agent_id, GridCoord1D coord) = 0;
|
||||
|
||||
/**
|
||||
* Remove agent from the grid.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
bool delete_agent(AgentID agent_id);
|
||||
/**
|
||||
* Remove agent from the grid.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
[[maybe_unused]] [[maybe_unused]] bool delete_agent(AgentID agent_id);
|
||||
|
||||
/**
|
||||
* Remove agent from the grid at the specified location
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
virtual bool delete_agent(AgentID agent_id, GridCoord1D coord);
|
||||
/**
|
||||
* Remove agent from the grid at the specified location
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
bool delete_agent(AgentID agent_id, const GridCoord1D &coord);
|
||||
|
||||
/**
|
||||
* Move an agent to the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to move.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*/
|
||||
bool move_agent(AgentID agent_id, GridCoord1D coord);
|
||||
/**
|
||||
* Move an agent to the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to move.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*/
|
||||
bool move_agent(AgentID agent_id, GridCoord1D coord);
|
||||
|
||||
/**
|
||||
* Inquire if the specified location is empty.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location has no `Agent`s occupying it, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool is_location_empty(GridCoord1D coord) const;
|
||||
/**
|
||||
* Inquire if the specified location is empty.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location has no `Agent`s occupying it, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_location_empty(const GridCoord1D& coord) const;
|
||||
|
||||
/**
|
||||
* Inquire if the specified location is valid within the grid.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location specified is valid, false otherwise.
|
||||
*/
|
||||
bool is_location_valid(GridCoord1D coord) const;
|
||||
/**
|
||||
* Inquire if the specified location is valid within the grid.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location specified is valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_location_valid(const GridCoord1D& coord) const;
|
||||
|
||||
/**
|
||||
* Get the location of the specified agent.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
*
|
||||
* @return the location of the specified `Agent`
|
||||
*/
|
||||
GridCoord1D get_location_by_agent(AgentID agent_id) const;
|
||||
/**
|
||||
* Get the location of the specified agent.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
*
|
||||
* @return the location of the specified `Agent`
|
||||
*/
|
||||
[[nodiscard]] GridCoord1D get_location_by_agent(AgentID agent_id) const;
|
||||
|
||||
/**
|
||||
* Get the contents of the specified location.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the
|
||||
* internal copy of the agent list at the location, therefore, any changes
|
||||
* to that object will update the state of the gird. Further, the pointer
|
||||
* should not be deleted when no longer used.
|
||||
*/
|
||||
std::vector<AgentID> *get_location_contents(GridCoord1D coord) const;
|
||||
/**
|
||||
* Get the contents of the specified location.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the
|
||||
* internal copy of the agent list at the location, therefore, any changes
|
||||
* to that object will update the state of the gird. Further, the pointer
|
||||
* should not be deleted when no longer used.
|
||||
*/
|
||||
[[nodiscard]] std::vector<AgentID> *get_location_contents(const GridCoord1D& coord) const;
|
||||
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `x` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
bool get_wrap_x(void) const;
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `x` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
[[maybe_unused]] [[maybe_unused]] [[nodiscard]] bool get_wrap_x() const;
|
||||
|
||||
/**
|
||||
* Return the neighborhood of the specified Agent
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*/
|
||||
std::vector<GridCoord1D> get_neighborhood(AgentID agent_id,
|
||||
bool include_center) const;
|
||||
/**
|
||||
* Return the neighborhood of the specified Agent
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*/
|
||||
[[nodiscard]] std::vector<GridCoord1D> get_neighborhood(AgentID agent_id, bool include_center) const;
|
||||
|
||||
/**
|
||||
* Return the neighborhood of the specified location
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
* @param[in] include_center should the center-point, occupied by the agent,
|
||||
* be in the list.
|
||||
*
|
||||
* @return a vector of `GridCoord1D` that includes all of the coordinates
|
||||
* for all adjacent points.
|
||||
*/
|
||||
std::vector<GridCoord1D> get_neighborhood(GridCoord1D coord,
|
||||
bool include_center) const;
|
||||
/**
|
||||
* Return the neighborhood of the specified location
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
* @param[in] include_center should the center-point, occupied by the agent,
|
||||
* be in the list.
|
||||
*
|
||||
* @return a vector of `GridCoord1D` that includes all of the coordinates
|
||||
* for all adjacent points.
|
||||
*/
|
||||
[[nodiscard]] std::vector<GridCoord1D> get_neighborhood(const GridCoord1D& coord, bool include_center) const;
|
||||
|
||||
/**
|
||||
* Get the size of the grid in the `x` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `x` dimension
|
||||
*/
|
||||
unsigned int get_maximum_x(void) const;
|
||||
/**
|
||||
* Get the size of the grid in the `x` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `x` dimension
|
||||
*/
|
||||
[[maybe_unused]] [[nodiscard]] unsigned int get_maximum_x() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assgined to this
|
||||
* grid.
|
||||
*/
|
||||
std::vector<AgentID> *_agent_grid;
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assigned to this
|
||||
* grid.
|
||||
*/
|
||||
std::vector<AgentID> *_agent_grid;
|
||||
|
||||
/**
|
||||
* A map containing the grid location of each agent.
|
||||
*/
|
||||
std::map<AgentID, GridCoord1D> *_agent_index;
|
||||
/**
|
||||
* A map containing the grid location of each agent.
|
||||
*/
|
||||
std::map<AgentID, GridCoord1D> *_agent_index;
|
||||
|
||||
/**
|
||||
* Automatically adjust a coordinate location for wrapping.
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
*
|
||||
* @return the adjusted coordinate wrapped if appropriate.
|
||||
*/
|
||||
GridCoord1D coord_wrap(GridCoord1D coord) const;
|
||||
/**
|
||||
* Automatically adjust a coordinate location for wrapping.
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
*
|
||||
* @return the adjusted coordinate wrapped if appropriate.
|
||||
*/
|
||||
[[nodiscard]] GridCoord1D coord_wrap(const GridCoord1D& coord) const;
|
||||
|
||||
private:
|
||||
unsigned int _maximum_x;
|
||||
bool _wrap_x;
|
||||
};
|
||||
private:
|
||||
unsigned int _maximum_x;
|
||||
bool _wrap_x;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -27,62 +27,62 @@
|
||||
#ifndef KAMI_GRID2D_H
|
||||
#define KAMI_GRID2D_H
|
||||
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
* Two-dimensional coordinates
|
||||
*/
|
||||
class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
|
||||
public:
|
||||
/**
|
||||
* Constructor for two-dimensional coordinates
|
||||
*/
|
||||
GridCoord2D(int x_coord, int y_coord)
|
||||
: _x_coord(x_coord), _y_coord(y_coord){};
|
||||
class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
|
||||
public:
|
||||
/**
|
||||
* Constructor for two-dimensional coordinates
|
||||
*/
|
||||
GridCoord2D(int x_coord, int y_coord)
|
||||
: _x_coord(x_coord), _y_coord(y_coord){};
|
||||
|
||||
/**
|
||||
* Get the coordinate in the first dimension or `x`.
|
||||
*/
|
||||
int get_x_location(void) const;
|
||||
/**
|
||||
* Get the coordinate in the first dimension or `x`.
|
||||
*/
|
||||
[[nodiscard]] int get_x_location() const;
|
||||
|
||||
/**
|
||||
* Get the coordinate in the second dimension or `y`.
|
||||
*/
|
||||
int get_y_location(void) const;
|
||||
/**
|
||||
* Get the coordinate in the second dimension or `y`.
|
||||
*/
|
||||
[[nodiscard]] int get_y_location() const;
|
||||
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
std::string to_string() const;
|
||||
/**
|
||||
* Convert the coordinate to a human-readable string.
|
||||
*
|
||||
* @return a human-readable form of the `Coord` as `std::string`.
|
||||
*/
|
||||
[[nodiscard]] std::string to_string() const override;
|
||||
|
||||
/**
|
||||
* Test if two coordinates are equal
|
||||
*/
|
||||
friend bool operator==(const GridCoord2D &, const GridCoord2D &);
|
||||
/**
|
||||
* Test if two coordinates are equal
|
||||
*/
|
||||
friend bool operator==(const GridCoord2D &, const GridCoord2D &);
|
||||
|
||||
/**
|
||||
* Test if two coordinates are not equal
|
||||
*/
|
||||
friend bool operator!=(const GridCoord2D &, const GridCoord2D &);
|
||||
/**
|
||||
* Test if two coordinates are not equal
|
||||
*/
|
||||
friend bool operator!=(const GridCoord2D &, const GridCoord2D &);
|
||||
|
||||
/**
|
||||
* Output a given coordinate to the specified stream
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &, const GridCoord2D &);
|
||||
/**
|
||||
* Output a given coordinate to the specified stream
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &, const GridCoord2D &);
|
||||
|
||||
private:
|
||||
int _x_coord, _y_coord;
|
||||
};
|
||||
private:
|
||||
int _x_coord, _y_coord;
|
||||
};
|
||||
|
||||
/**
|
||||
* A two-dimensional grid where each cell may contain agents
|
||||
@@ -92,191 +92,187 @@ class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
|
||||
* @see `MultiGrid2D`
|
||||
* @see `SoloGrid2D`
|
||||
*/
|
||||
class LIBKAMI_EXPORT Grid2D : public GridDomain {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first
|
||||
* dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second
|
||||
* dimension
|
||||
*/
|
||||
Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x = false,
|
||||
bool wrap_y = false);
|
||||
class LIBKAMI_EXPORT Grid2D : public GridDomain {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first
|
||||
* dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second
|
||||
* dimension
|
||||
*/
|
||||
Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x = false,
|
||||
bool wrap_y = false);
|
||||
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
virtual ~Grid2D();
|
||||
/**
|
||||
* Deconstructor
|
||||
*/
|
||||
virtual ~Grid2D();
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true.
|
||||
*/
|
||||
virtual bool add_agent(AgentID agent_id, GridCoord2D coord) = 0;
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true.
|
||||
*/
|
||||
virtual bool add_agent(AgentID agent_id, GridCoord2D coord) = 0;
|
||||
|
||||
/**
|
||||
* Remove agent from the grid.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
bool delete_agent(AgentID agent_id);
|
||||
/**
|
||||
* Remove agent from the grid.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
[[maybe_unused]] bool delete_agent(AgentID agent_id);
|
||||
|
||||
/**
|
||||
* Remove agent from the grid at the specified location
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
virtual bool delete_agent(AgentID agent_id, GridCoord2D coord);
|
||||
/**
|
||||
* Remove agent from the grid at the specified location
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to remove.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not removed, otherwise, true.
|
||||
*/
|
||||
bool delete_agent(AgentID agent_id, const GridCoord2D &coord);
|
||||
|
||||
/**
|
||||
* Move an agent to the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to move.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*/
|
||||
bool move_agent(AgentID agent_id, GridCoord2D coord);
|
||||
/**
|
||||
* Move an agent to the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to move.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*/
|
||||
bool move_agent(AgentID agent_id, GridCoord2D coord);
|
||||
|
||||
/**
|
||||
* Inquire if the specified location is empty.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location has no `Agent`s occupying it, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool is_location_empty(GridCoord2D coord) const;
|
||||
/**
|
||||
* Inquire if the specified location is empty.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location has no `Agent`s occupying it, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_location_empty(const GridCoord2D& coord) const;
|
||||
|
||||
/**
|
||||
* Inquire if the specified location is valid within the grid.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location specified is valid, false otherwise.
|
||||
*/
|
||||
bool is_location_valid(GridCoord2D coord) const;
|
||||
/**
|
||||
* Inquire if the specified location is valid within the grid.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return true if the location specified is valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_location_valid(const GridCoord2D& coord) const;
|
||||
|
||||
/**
|
||||
* Get the location of the specified agent.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
*
|
||||
* @return the location of the specified `Agent`
|
||||
*/
|
||||
GridCoord2D get_location_by_agent(AgentID agent_id) const;
|
||||
/**
|
||||
* Get the location of the specified agent.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
*
|
||||
* @return the location of the specified `Agent`
|
||||
*/
|
||||
[[nodiscard]] GridCoord2D get_location_by_agent(AgentID agent_id) const;
|
||||
|
||||
/**
|
||||
* Get the contents of the specified location.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the
|
||||
* internal copy of the agent list at the location, therefore, any changes
|
||||
* to that object will update the state of the gird. Further, the pointer
|
||||
* should not be deleted when no longer used.
|
||||
*/
|
||||
std::vector<AgentID> *get_location_contents(GridCoord2D coord) const;
|
||||
/**
|
||||
* Get the contents of the specified location.
|
||||
*
|
||||
* @param[in] coord the coordinates of the query.
|
||||
*
|
||||
* @return a pointer to a `vector` of `AgentID`s. The pointer is to the
|
||||
* internal copy of the agent list at the location, therefore, any changes
|
||||
* to that object will update the state of the gird. Further, the pointer
|
||||
* should not be deleted when no longer used.
|
||||
*/
|
||||
[[nodiscard]] std::vector<AgentID> *get_location_contents(const GridCoord2D& coord) const;
|
||||
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `x` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
bool get_wrap_x(void) const;
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `x` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
[[maybe_unused]] [[nodiscard]] bool get_wrap_x() const;
|
||||
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `y` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
bool get_wrap_y(void) const;
|
||||
/**
|
||||
* Inquire to whether the grid wraps in the `y` dimension.
|
||||
*
|
||||
* @return true if the grid wraps, and false otherwise
|
||||
*/
|
||||
[[maybe_unused]] [[nodiscard]] bool get_wrap_y() const;
|
||||
|
||||
/**
|
||||
* Return the neighborhood of the specified Agent
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
* @param[in] neighborhood_type the neighborhood type.
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*
|
||||
* @see `NeighborhoodType`
|
||||
*/
|
||||
std::vector<GridCoord2D> get_neighborhood(
|
||||
AgentID agent_id, GridNeighborhoodType neighborhood_type,
|
||||
bool include_center) const;
|
||||
/**
|
||||
* Return the neighborhood of the specified Agent
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent in question.
|
||||
* @param[in] neighborhood_type the neighborhood type.
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*
|
||||
* @see `NeighborhoodType`
|
||||
*/
|
||||
[[nodiscard]] std::vector<GridCoord2D> get_neighborhood(AgentID agent_id, GridNeighborhoodType neighborhood_type, bool include_center) const;
|
||||
|
||||
/**
|
||||
* Return the neighborhood of the specified location
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
* @param[in] neighborhood_type the neighborhood type.
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*
|
||||
* @see `NeighborhoodType`
|
||||
*/
|
||||
std::vector<GridCoord2D> get_neighborhood(
|
||||
GridCoord2D coord, GridNeighborhoodType neighborhood_type,
|
||||
bool include_center) const;
|
||||
/**
|
||||
* Return the neighborhood of the specified location
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
* @param[in] neighborhood_type the neighborhood type.
|
||||
* @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
|
||||
* for all adjacent points.
|
||||
*
|
||||
* @see `NeighborhoodType`
|
||||
*/
|
||||
[[nodiscard]] std::vector<GridCoord2D> get_neighborhood(const GridCoord2D& coord, GridNeighborhoodType neighborhood_type, bool include_center) const;
|
||||
|
||||
/**
|
||||
* Get the size of the grid in the `x` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `x` dimension
|
||||
*/
|
||||
unsigned int get_maximum_x(void) const;
|
||||
/**
|
||||
* Get the size of the grid in the `x` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `x` dimension
|
||||
*/
|
||||
[[maybe_unused]] [[nodiscard]] unsigned int get_maximum_x() const;
|
||||
|
||||
/**
|
||||
* Get the size of the grid in the `y` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `xy dimension
|
||||
*/
|
||||
unsigned int get_maximum_y(void) const;
|
||||
/**
|
||||
* Get the size of the grid in the `y` dimension.
|
||||
*
|
||||
* @return the length of the grid in the `xy dimension
|
||||
*/
|
||||
[[maybe_unused]] [[nodiscard]] unsigned int get_maximum_y() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assgined to this
|
||||
* grid.
|
||||
*/
|
||||
std::vector<AgentID> **_agent_grid;
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assigned to this
|
||||
* grid.
|
||||
*/
|
||||
std::vector<AgentID> **_agent_grid;
|
||||
|
||||
/**
|
||||
* A map containing the grid location of each agent.
|
||||
*/
|
||||
std::map<AgentID, GridCoord2D> *_agent_index;
|
||||
/**
|
||||
* A map containing the grid location of each agent.
|
||||
*/
|
||||
std::map<AgentID, GridCoord2D> *_agent_index;
|
||||
|
||||
/**
|
||||
* Automatically adjust a coordinate location for wrapping.
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
*
|
||||
* @return the adjusted coordinate wrapped if appropriate.
|
||||
*/
|
||||
GridCoord2D coord_wrap(GridCoord2D coord) const;
|
||||
/**
|
||||
* Automatically adjust a coordinate location for wrapping.
|
||||
*
|
||||
* @param[in] coord the coordinates of the specified location.
|
||||
*
|
||||
* @return the adjusted coordinate wrapped if appropriate.
|
||||
*/
|
||||
[[nodiscard]] GridCoord2D coord_wrap(const GridCoord2D& coord) const;
|
||||
|
||||
private:
|
||||
unsigned int _maximum_x, _maximum_y;
|
||||
bool _wrap_x, _wrap_y;
|
||||
};
|
||||
private:
|
||||
unsigned int _maximum_x, _maximum_y;
|
||||
bool _wrap_x, _wrap_y;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -35,34 +35,34 @@ namespace kami {
|
||||
/**
|
||||
* An abstract for generic models
|
||||
*/
|
||||
class LIBKAMI_EXPORT Model {
|
||||
public:
|
||||
/**
|
||||
* Get a reference to an `Agent` by `AgentID`
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` to search for.
|
||||
*
|
||||
* @return a reference to the desired `Agent` or `nullptr` if not found.
|
||||
*/
|
||||
virtual Agent *get_agent_by_id(AgentID agent_id) const = 0;
|
||||
class LIBKAMI_EXPORT Model {
|
||||
public:
|
||||
/**
|
||||
* Get a reference to an `Agent` by `AgentID`
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` to search for.
|
||||
*
|
||||
* @return a reference to the desired `Agent` or `nullptr` if not found.
|
||||
*/
|
||||
[[nodiscard]] virtual Agent *get_agent_by_id(AgentID agent_id) const = 0;
|
||||
|
||||
/**
|
||||
* Execute a fixed number of time-steps for the model.
|
||||
*
|
||||
* This function should execute a fixed number of time-steps for the model.
|
||||
*
|
||||
* @param[in] n the number of time steps to execute.
|
||||
*/
|
||||
virtual void run(unsigned int n) = 0;
|
||||
/**
|
||||
* Execute a fixed number of time-steps for the model.
|
||||
*
|
||||
* This function should execute a fixed number of time-steps for the model.
|
||||
*
|
||||
* @param[in] n the number of time steps to execute.
|
||||
*/
|
||||
[[maybe_unused]] virtual void run(unsigned int n) = 0;
|
||||
|
||||
/**
|
||||
* Execute a single time-step for the model.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
};
|
||||
/**
|
||||
* Execute a single time-step for the model.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -40,28 +40,28 @@ namespace kami {
|
||||
*
|
||||
* @details The grid is linear and may wrap around in its only dimension.
|
||||
*/
|
||||
class LIBKAMI_EXPORT MultiGrid1D : public Grid1D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
MultiGrid1D(unsigned int maximum_x, bool wrap_x)
|
||||
: Grid1D(maximum_x, wrap_x) {}
|
||||
class LIBKAMI_EXPORT MultiGrid1D : public Grid1D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
MultiGrid1D(unsigned int maximum_x, bool wrap_x)
|
||||
: Grid1D(maximum_x, wrap_x) {}
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord1D coord);
|
||||
};
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord1D coord) override;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -43,32 +43,32 @@ namespace kami {
|
||||
* @see `Grid2D`
|
||||
* @see `SoloGrid2D`
|
||||
*/
|
||||
class LIBKAMI_EXPORT MultiGrid2D : public Grid2D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first
|
||||
* dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second
|
||||
* dimension
|
||||
*/
|
||||
MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
|
||||
bool wrap_y);
|
||||
class LIBKAMI_EXPORT MultiGrid2D : public Grid2D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first
|
||||
* dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second
|
||||
* dimension
|
||||
*/
|
||||
MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y)
|
||||
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {};
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord2D coord);
|
||||
};
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord2D coord) override;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -37,71 +37,60 @@
|
||||
|
||||
namespace kami {
|
||||
|
||||
/*
|
||||
/**
|
||||
* Will execute all agent steps in a random order.
|
||||
*
|
||||
* A random scheduler will iterate over the agents assigned
|
||||
* to the scheduler and call their `step()` function in a random order.
|
||||
* That order should be different for each subsequent call to `step()`,
|
||||
* but is not gauranteed not to repeat.
|
||||
* A random scheduler will iterate over the agents assigned
|
||||
* to the scheduler and call their `step()` function in a random order.
|
||||
* That order should be different for each subsequent call to `step()`,
|
||||
* but is not guaranteed not to repeat.
|
||||
*
|
||||
* @note First create a Model for the scheduler to live in.
|
||||
*/
|
||||
class LIBKAMI_EXPORT RandomScheduler : public SequentialScheduler {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @details The `model` parameter is used by the scheduler to get
|
||||
* access to an `Agent`. The `Model` is presumed to maintain a master
|
||||
* list of all `Agent`s in the `Model` and the `Model` can be queried for
|
||||
* a reference to any particular `Agent` at `step()` time.
|
||||
*
|
||||
* @param model [in] A reference to the model the scheduler is timing.
|
||||
*/
|
||||
RandomScheduler(Model *model);
|
||||
class LIBKAMI_EXPORT RandomScheduler : public SequentialScheduler {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @details The `model` parameter is used by the scheduler to get
|
||||
* access to an `Agent`. The `Model` is presumed to maintain a master
|
||||
* list of all `Agent`s in the `Model` and the `Model` can be queried for
|
||||
* a reference to any particular `Agent` at `step()` time.
|
||||
*
|
||||
* @param model [in] A reference to the model the scheduler is timing.
|
||||
* @param rng [in] A uniform random number generator of type
|
||||
* `std::mt19937`, used as the source of randomness.
|
||||
*/
|
||||
RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng);
|
||||
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @details The `model` parameter is used by the scheduler to get
|
||||
* access to an `Agent`. The `Model` is presumed to maintain a master
|
||||
* list of all `Agent`s in the `Model` and the `Model` can be queried for
|
||||
* a reference to any particular `Agent` at `step()` time.
|
||||
*
|
||||
* @param model [in] A reference to the model the scheduler is timing.
|
||||
* @param rng [in] A uniform random number generator of type
|
||||
* `std::mt19937`, used as the source of randomness.
|
||||
*/
|
||||
RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng);
|
||||
/**
|
||||
* @brief Execute a single time step.
|
||||
*
|
||||
* @details This method will randomize the list of Agents in the scheduler's
|
||||
* internal queue and then execute the `Agent::step()` method for every
|
||||
* Agent assigned to this scheduler in the randomized order.
|
||||
*/
|
||||
void step() override;
|
||||
|
||||
/**
|
||||
* @brief Execute a single time step.
|
||||
*
|
||||
* @details This method will randomize the list of Agents in the scheduler's
|
||||
* internal queue and then execute the `Agent::step()` method for every
|
||||
* Agent assigned to this scheduler in the randomized order.
|
||||
*/
|
||||
void step();
|
||||
/**
|
||||
* Set the random number generator used to randomize the order of agent
|
||||
* stepping.
|
||||
*
|
||||
* @param rng [in] A uniform random number generator of type `std::mt19937`,
|
||||
* used as the source of randomness.
|
||||
*/
|
||||
void set_rng(std::shared_ptr<std::mt19937> rng);
|
||||
|
||||
/**
|
||||
* Set the random number generator used to randomize the order of agent
|
||||
* stepping.
|
||||
*
|
||||
* @param rng [in] A uniform random number generator of type `std::mt19937`,
|
||||
* used as the source of randomness.
|
||||
*/
|
||||
void set_rng(std::shared_ptr<std::mt19937> rng);
|
||||
/**
|
||||
* Get a reference to the random number generator used to randomize
|
||||
* the order of agent stepping.
|
||||
*/
|
||||
[[maybe_unused]] std::shared_ptr<std::mt19937> get_rng();
|
||||
|
||||
/**
|
||||
* Get a reference to the random number generator used to randomize
|
||||
* the order of agent stepping.
|
||||
*/
|
||||
std::shared_ptr<std::mt19937> get_rng();
|
||||
private:
|
||||
std::shared_ptr<std::mt19937> _rng;
|
||||
};
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::mt19937> _rng;
|
||||
};
|
||||
|
||||
}; // namespace kami
|
||||
} // namespace kami
|
||||
|
||||
#endif // KAMI_RANDOM_H
|
||||
|
||||
@@ -39,29 +39,29 @@ namespace kami {
|
||||
* scheduler will have a collection of agents assigned to it and will execute
|
||||
* the step function for each agent based on the type of scheduling implemented.
|
||||
*/
|
||||
class LIBKAMI_EXPORT Scheduler {
|
||||
public:
|
||||
/**
|
||||
* Add an Agent to the Scheduler.
|
||||
*
|
||||
* @param agent_id The AgentID of the agent to add.
|
||||
*/
|
||||
virtual void add_agent(AgentID agent_id) = 0;
|
||||
class LIBKAMI_EXPORT Scheduler {
|
||||
public:
|
||||
/**
|
||||
* Add an Agent to the Scheduler.
|
||||
*
|
||||
* @param agent_id The AgentID of the agent to add.
|
||||
*/
|
||||
virtual void add_agent(AgentID agent_id) = 0;
|
||||
|
||||
/**
|
||||
* Remove an Agent from the Scheduler.
|
||||
*
|
||||
* @param agent_id The AgentID of the agent to remove.
|
||||
*/
|
||||
virtual void delete_agent(AgentID agent_id) = 0;
|
||||
/**
|
||||
* Remove an Agent from the Scheduler.
|
||||
*
|
||||
* @param agent_id The AgentID of the agent to remove.
|
||||
*/
|
||||
[[maybe_unused]] virtual void delete_agent(AgentID agent_id) = 0;
|
||||
|
||||
/**
|
||||
* Step the Scheduler.
|
||||
*
|
||||
* A generic step function that executes a single time step.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
};
|
||||
/**
|
||||
* Step the Scheduler.
|
||||
*
|
||||
* A generic step function that executes a single time step.
|
||||
*/
|
||||
virtual void step() = 0;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
#ifndef KAMI_SEQUENTIAL_H
|
||||
#define KAMI_SEQUENTIAL_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <kami/KAMI_EXPORT.h>
|
||||
#include <kami/agent.h>
|
||||
#include <kami/model.h>
|
||||
#include <kami/scheduler.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
@@ -47,62 +47,62 @@ namespace kami {
|
||||
*
|
||||
* \pre First create a Model for the scheduler to live in.
|
||||
*/
|
||||
class LIBKAMI_EXPORT SequentialScheduler : public Scheduler {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @details The Model parameter is used by the scheduler to get
|
||||
* access to an Agent. The Model is presumed to maintain a master
|
||||
* list of all Agents in the Model and the Model can be queried for
|
||||
* a reference to any particular Agent at `step()` time.
|
||||
*/
|
||||
SequentialScheduler(Model *model);
|
||||
class LIBKAMI_EXPORT SequentialScheduler : public Scheduler {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor.
|
||||
*
|
||||
* @details The Model parameter is used by the scheduler to get
|
||||
* access to an Agent. The Model is presumed to maintain a master
|
||||
* list of all Agents in the Model and the Model can be queried for
|
||||
* a reference to any particular Agent at `step()` time.
|
||||
*/
|
||||
explicit SequentialScheduler(Model *model);
|
||||
|
||||
/**
|
||||
* @brief Add an agent to the scheduler.
|
||||
*
|
||||
* @details The scheduler maintains a list of all AgentIDs currently
|
||||
* assigned. This function adds a new Agent to the list.
|
||||
*/
|
||||
void add_agent(AgentID agent_id);
|
||||
/**
|
||||
* @brief Add an agent to the scheduler.
|
||||
*
|
||||
* @details The scheduler maintains a list of all AgentIDs currently
|
||||
* assigned. This function adds a new Agent to the list.
|
||||
*/
|
||||
void add_agent(AgentID agent_id) override;
|
||||
|
||||
/**
|
||||
* @brief Remove an agent from the scheduler.
|
||||
*
|
||||
* @details The scheduler maintains a list of all AgentIDs currently
|
||||
* assigned. This function removes an Agent from the list.
|
||||
*/
|
||||
void delete_agent(AgentID agent_id);
|
||||
/**
|
||||
* @brief Remove an agent from the scheduler.
|
||||
*
|
||||
* @details The scheduler maintains a list of all AgentIDs currently
|
||||
* assigned. This function removes an Agent from the list.
|
||||
*/
|
||||
void delete_agent(AgentID agent_id) override;
|
||||
|
||||
/**
|
||||
* @brief Execute a single time step.
|
||||
*
|
||||
* @details This method will step through the list of Agents in the
|
||||
* scheduler's internal queue and then execute the `Agent::step()`
|
||||
* method for every Agent assigned to this scheduler in the order
|
||||
* assigned.
|
||||
*/
|
||||
void step();
|
||||
/**
|
||||
* @brief Execute a single time step.
|
||||
*
|
||||
* @details This method will step through the list of Agents in the
|
||||
* scheduler's internal queue and then execute the `Agent::step()`
|
||||
* method for every Agent assigned to this scheduler in the order
|
||||
* assigned.
|
||||
*/
|
||||
void step() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assgined to this
|
||||
* scheduler
|
||||
*/
|
||||
std::vector<AgentID> _agent_list;
|
||||
protected:
|
||||
/**
|
||||
* A vector containing the `AgentID`s of all agents assigned to this
|
||||
* scheduler
|
||||
*/
|
||||
std::vector<AgentID> _agent_list;
|
||||
|
||||
/**
|
||||
* A pointer to the `Model` this scehduler belongs to
|
||||
*/
|
||||
Model *_model;
|
||||
/**
|
||||
* A pointer to the `Model` this scheduler belongs to
|
||||
*/
|
||||
Model *_model;
|
||||
|
||||
/**
|
||||
* Counter to increment on each step
|
||||
*/
|
||||
int _step_counter;
|
||||
};
|
||||
/**
|
||||
* Counter to increment on each step
|
||||
*/
|
||||
int _step_counter;
|
||||
};
|
||||
|
||||
}; // namespace kami
|
||||
} // namespace kami
|
||||
|
||||
#endif // KAMI_SEQUENTIAL_H
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
#include <kami/KAMI_EXPORT.h>
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid1d.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
@@ -41,28 +39,28 @@ namespace kami {
|
||||
*
|
||||
* @details The grid is linear and may wrap around in its only dimension.
|
||||
*/
|
||||
class LIBKAMI_EXPORT SoloGrid1D : public Grid1D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
SoloGrid1D(unsigned int maximum_x, bool wrap_x)
|
||||
: Grid1D(maximum_x, wrap_x) {}
|
||||
class LIBKAMI_EXPORT SoloGrid1D : public Grid1D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid.
|
||||
* @param[in] wrap_x should the grid wrap around on itself.
|
||||
*/
|
||||
SoloGrid1D(unsigned int maximum_x, bool wrap_x)
|
||||
: Grid1D(maximum_x, wrap_x) {}
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord1D coord);
|
||||
};
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord1D coord) override;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -27,14 +27,11 @@
|
||||
#ifndef KAMI_SOLOGRID2D_H
|
||||
#define KAMI_SOLOGRID2D_H
|
||||
|
||||
#include <kami/KAMI_EXPORT.h>
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid2d.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace kami {
|
||||
|
||||
/**
|
||||
@@ -45,30 +42,30 @@ namespace kami {
|
||||
* @see `MultiGrid2D`
|
||||
* @see `Grid2D`
|
||||
*/
|
||||
class LIBKAMI_EXPORT SoloGrid2D : public Grid2D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second dimension
|
||||
*/
|
||||
SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
|
||||
bool wrap_y);
|
||||
class LIBKAMI_EXPORT SoloGrid2D : public Grid2D {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param[in] maximum_x the length of the grid in the first dimension
|
||||
* @param[in] maximum_y the length of the grid in the second dimension
|
||||
* @param[in] wrap_x should the grid wrap around on itself in the first dimension
|
||||
* @param[in] wrap_y should the grid wrap around on itself in the second dimension
|
||||
*/
|
||||
SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y)
|
||||
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {};
|
||||
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord2D coord);
|
||||
};
|
||||
/**
|
||||
* Place agent on the grid at the specified location.
|
||||
*
|
||||
* @param[in] agent_id the `AgentID` of the agent to add.
|
||||
* @param[in] coord the coordinates of the agent.
|
||||
*
|
||||
* @returns false if the agent is not placed at the specified
|
||||
* location, otherwise, true
|
||||
*/
|
||||
bool add_agent(AgentID agent_id, GridCoord2D coord) override;
|
||||
};
|
||||
|
||||
} // namespace kami
|
||||
|
||||
|
||||
@@ -46,54 +46,54 @@ namespace kami {
|
||||
*
|
||||
* @note First create a Model for the scheduler to live in.
|
||||
*/
|
||||
class LIBKAMI_EXPORT StagedScheduler : public Scheduler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* The Model parameter is used by the scheduler to get access to an Agent.
|
||||
* The Model is presumed to maintain a master list of all Agents in the
|
||||
* Model and the Model can be queried for a reference to any particular
|
||||
* Agent at `step()` time.
|
||||
*/
|
||||
StagedScheduler(Model *);
|
||||
class LIBKAMI_EXPORT StagedScheduler : public Scheduler {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* The Model parameter is used by the scheduler to get access to an Agent.
|
||||
* The Model is presumed to maintain a master list of all Agents in the
|
||||
* Model and the Model can be queried for a reference to any particular
|
||||
* Agent at `step()` time.
|
||||
*/
|
||||
explicit StagedScheduler(Model *);
|
||||
|
||||
/**
|
||||
* A deconstructor.
|
||||
*/
|
||||
virtual ~StagedScheduler();
|
||||
/**
|
||||
* A deconstructor.
|
||||
*/
|
||||
~StagedScheduler() = default;
|
||||
|
||||
/**
|
||||
* Add an agent to the scheduler.
|
||||
*
|
||||
* The scheduler maintains a list of all AgentIDs currently assigned. This
|
||||
* function adds a new Agent to the list.
|
||||
*/
|
||||
void add_agent(AgentID agent_id);
|
||||
/**
|
||||
* Add an agent to the scheduler.
|
||||
*
|
||||
* The scheduler maintains a list of all AgentIDs currently assigned. This
|
||||
* function adds a new Agent to the list.
|
||||
*/
|
||||
void add_agent(AgentID agent_id) override;
|
||||
|
||||
/**
|
||||
* Remove an agent from the scheduler.
|
||||
*
|
||||
* The scheduler maintains a list of all AgentIDs currently assigned. This
|
||||
* function removes an Agent from the list.
|
||||
*/
|
||||
void delete_agent(AgentID agent_id);
|
||||
/**
|
||||
* Remove an agent from the scheduler.
|
||||
*
|
||||
* The scheduler maintains a list of all AgentIDs currently assigned. This
|
||||
* function removes an Agent from the list.
|
||||
*/
|
||||
void delete_agent(AgentID agent_id) override;
|
||||
|
||||
/**
|
||||
* Execute a single time step.
|
||||
*
|
||||
* This method will step through the list of Agents in the scheduler's
|
||||
* internal queue and execute the `Agent::step()` method for each `Agent`
|
||||
* in the same order. Finally, it will execute the `Agent::advance()`
|
||||
* method for each Agent in the same order.
|
||||
*/
|
||||
void step();
|
||||
/**
|
||||
* Execute a single time step.
|
||||
*
|
||||
* This method will step through the list of Agents in the scheduler's
|
||||
* internal queue and execute the `Agent::step()` method for each `Agent`
|
||||
* in the same order. Finally, it will execute the `Agent::advance()`
|
||||
* method for each Agent in the same order.
|
||||
*/
|
||||
void step() override;
|
||||
|
||||
private:
|
||||
std::vector<AgentID> _agent_list;
|
||||
Model *_model;
|
||||
int _step_counter;
|
||||
};
|
||||
private:
|
||||
std::vector<AgentID> _agent_list;
|
||||
Model *_model;
|
||||
int _step_counter;
|
||||
};
|
||||
|
||||
}; // namespace kami
|
||||
} // namespace kami
|
||||
|
||||
#endif // KAMI_STAGED_H
|
||||
|
||||
@@ -30,28 +30,28 @@
|
||||
|
||||
namespace kami {
|
||||
|
||||
bool operator==(const AgentID &lhs, const AgentID &rhs) {
|
||||
return lhs._id == rhs._id;
|
||||
}
|
||||
bool operator==(const AgentID &lhs, const AgentID &rhs) {
|
||||
return lhs._id == rhs._id;
|
||||
}
|
||||
|
||||
bool operator!=(const AgentID &lhs, const AgentID &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
bool operator!=(const AgentID &lhs, const AgentID &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const AgentID &lhs, const AgentID &rhs) {
|
||||
return lhs._id < rhs._id;
|
||||
}
|
||||
bool operator<(const AgentID &lhs, const AgentID &rhs) {
|
||||
return lhs._id < rhs._id;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
|
||||
AgentID Agent::get_agent_id() const { return this->_agent_id; }
|
||||
AgentID Agent::get_agent_id() const { return this->_agent_id; }
|
||||
|
||||
bool operator==(const Agent &lhs, const Agent &rhs) {
|
||||
return lhs._agent_id == rhs._agent_id;
|
||||
}
|
||||
bool operator==(const Agent &lhs, const Agent &rhs) {
|
||||
return lhs._agent_id == rhs._agent_id;
|
||||
}
|
||||
|
||||
bool operator!=(const Agent &lhs, const Agent &rhs) { return !(lhs == rhs); }
|
||||
bool operator!=(const Agent &lhs, const Agent &rhs) { return !(lhs == rhs); }
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
|
||||
namespace kami {
|
||||
|
||||
std::ostream &operator<<(std::ostream &lhs, const Coord &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &lhs, const Coord &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -25,135 +25,132 @@
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid1d.h>
|
||||
#include <kami/kami.h>
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace kami {
|
||||
|
||||
int GridCoord1D::get_x_location() const { return _x_coord; }
|
||||
int GridCoord1D::get_x_location() const { return _x_coord; }
|
||||
|
||||
std::string GridCoord1D::to_string() const {
|
||||
return std::string("(" + std::to_string(_x_coord) + ")");
|
||||
}
|
||||
std::string GridCoord1D::to_string() const {
|
||||
return std::string("(" + std::to_string(_x_coord) + ")");
|
||||
}
|
||||
|
||||
bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs) {
|
||||
return (lhs._x_coord == rhs._x_coord);
|
||||
}
|
||||
bool operator==(const GridCoord1D &lhs, const GridCoord1D &rhs) {
|
||||
return (lhs._x_coord == rhs._x_coord);
|
||||
}
|
||||
|
||||
bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
bool operator!=(const GridCoord1D &lhs, const GridCoord1D &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
|
||||
Grid1D::Grid1D(unsigned int maximum_x, bool wrap_x) {
|
||||
_agent_grid = new std::vector<AgentID>[maximum_x];
|
||||
_agent_index = new std::map<AgentID, GridCoord1D>;
|
||||
|
||||
_maximum_x = maximum_x;
|
||||
_wrap_x = wrap_x;
|
||||
}
|
||||
Grid1D::Grid1D(unsigned int maximum_x, bool wrap_x) {
|
||||
_agent_grid = new std::vector<AgentID>[maximum_x];
|
||||
_agent_index = new std::map<AgentID, GridCoord1D>;
|
||||
|
||||
Grid1D::~Grid1D(void) {
|
||||
delete _agent_index;
|
||||
delete[] _agent_grid;
|
||||
}
|
||||
_maximum_x = maximum_x;
|
||||
_wrap_x = wrap_x;
|
||||
}
|
||||
|
||||
bool Grid1D::delete_agent(AgentID agent_id) {
|
||||
GridCoord1D coord = get_location_by_agent(agent_id);
|
||||
Grid1D::~Grid1D() {
|
||||
delete _agent_index;
|
||||
delete[] _agent_grid;
|
||||
}
|
||||
|
||||
return delete_agent(agent_id, coord);
|
||||
}
|
||||
[[maybe_unused]] bool Grid1D::delete_agent(AgentID agent_id) {
|
||||
GridCoord1D coord = get_location_by_agent(agent_id);
|
||||
|
||||
bool Grid1D::is_location_valid(GridCoord1D coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
return (x >= 0 && x < static_cast<int>(_maximum_x));
|
||||
}
|
||||
return delete_agent(agent_id, coord);
|
||||
}
|
||||
|
||||
bool Grid1D::is_location_empty(GridCoord1D coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
bool Grid1D::is_location_valid(const GridCoord1D& coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
return (x >= 0 && x < static_cast<int>(_maximum_x));
|
||||
}
|
||||
|
||||
return _agent_grid[x].size() == 0;
|
||||
}
|
||||
bool Grid1D::is_location_empty(const GridCoord1D &coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
|
||||
bool Grid1D::delete_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())];
|
||||
return _agent_grid[x].empty();
|
||||
}
|
||||
|
||||
for (auto test_agent_id = agent_list.begin();
|
||||
test_agent_id < agent_list.end(); test_agent_id++) {
|
||||
if (*test_agent_id == agent_id) {
|
||||
agent_list.erase(test_agent_id);
|
||||
_agent_index->erase(agent_id);
|
||||
return true;
|
||||
bool Grid1D::delete_agent(AgentID agent_id, const GridCoord1D &coord) {
|
||||
auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())];
|
||||
|
||||
for (auto test_agent_id = agent_list.begin();
|
||||
test_agent_id < agent_list.end(); test_agent_id++) {
|
||||
if (*test_agent_id == agent_id) {
|
||||
agent_list.erase(test_agent_id);
|
||||
_agent_index->erase(agent_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool Grid1D::move_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
GridCoord1D coord_current = get_location_by_agent(agent_id);
|
||||
|
||||
bool Grid1D::move_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
GridCoord1D coord_current = get_location_by_agent(agent_id);
|
||||
|
||||
if (delete_agent(agent_id, coord_current) == true)
|
||||
return add_agent(agent_id, coord);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<GridCoord1D> Grid1D::get_neighborhood(AgentID agent_id,
|
||||
bool include_center) const {
|
||||
GridCoord1D coord = get_location_by_agent(agent_id);
|
||||
|
||||
return get_neighborhood(coord, include_center);
|
||||
}
|
||||
|
||||
std::vector<GridCoord1D> Grid1D::get_neighborhood(GridCoord1D coord,
|
||||
bool include_center) const {
|
||||
std::vector<GridCoord1D> neighborhood;
|
||||
auto x = coord.get_x_location();
|
||||
|
||||
// We assume our starting position is valid
|
||||
if (include_center == true) neighborhood.push_back(coord);
|
||||
|
||||
// E, W
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord1D(x + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord1D(x - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
if (delete_agent(agent_id, coord_current))
|
||||
return add_agent(agent_id, std::move(coord));
|
||||
return false;
|
||||
}
|
||||
|
||||
return neighborhood;
|
||||
}
|
||||
std::vector<GridCoord1D> Grid1D::get_neighborhood(AgentID agent_id, bool include_center) const {
|
||||
GridCoord1D coord = get_location_by_agent(agent_id);
|
||||
|
||||
std::vector<AgentID> *Grid1D::get_location_contents(GridCoord1D coord) const {
|
||||
if (is_location_valid(coord)) return &_agent_grid[coord.get_x_location()];
|
||||
return nullptr;
|
||||
}
|
||||
return get_neighborhood(coord, include_center);
|
||||
}
|
||||
|
||||
bool Grid1D::get_wrap_x(void) const { return _wrap_x; }
|
||||
std::vector<GridCoord1D> Grid1D::get_neighborhood(const GridCoord1D& coord, bool include_center) const {
|
||||
std::vector<GridCoord1D> neighborhood;
|
||||
auto x = coord.get_x_location();
|
||||
|
||||
unsigned int Grid1D::get_maximum_x(void) const { return _maximum_x; }
|
||||
// We assume our starting position is valid
|
||||
if (include_center) neighborhood.push_back(coord);
|
||||
|
||||
GridCoord1D Grid1D::get_location_by_agent(AgentID agent_id) const {
|
||||
return _agent_index->at(agent_id);
|
||||
}
|
||||
// E, W
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord1D(x + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord1D(x - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
|
||||
GridCoord1D Grid1D::coord_wrap(GridCoord1D coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
if (_wrap_x == true)
|
||||
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
|
||||
return GridCoord1D(x);
|
||||
}
|
||||
std::vector<AgentID> *Grid1D::get_location_contents(const GridCoord1D& coord) const {
|
||||
if (is_location_valid(coord)) return &_agent_grid[coord.get_x_location()];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool Grid1D::get_wrap_x() const { return _wrap_x; }
|
||||
|
||||
[[maybe_unused]] unsigned int Grid1D::get_maximum_x() const { return _maximum_x; }
|
||||
|
||||
GridCoord1D Grid1D::get_location_by_agent(AgentID agent_id) const {
|
||||
return _agent_index->at(agent_id);
|
||||
}
|
||||
|
||||
GridCoord1D Grid1D::coord_wrap(const GridCoord1D& coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
|
||||
if(_wrap_x)
|
||||
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
|
||||
return GridCoord1D(x);
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -23,202 +23,198 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid2d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace kami {
|
||||
|
||||
int GridCoord2D::get_x_location(void) const {
|
||||
return _x_coord;
|
||||
}
|
||||
int GridCoord2D::get_x_location() const {
|
||||
return _x_coord;
|
||||
}
|
||||
|
||||
int GridCoord2D::get_y_location(void) const {
|
||||
return _y_coord;
|
||||
}
|
||||
int GridCoord2D::get_y_location() const {
|
||||
return _y_coord;
|
||||
}
|
||||
|
||||
std::string GridCoord2D::to_string() const {
|
||||
return std::string("(" + std::to_string(_x_coord) + ", " +
|
||||
std::to_string(_y_coord) + ")");
|
||||
}
|
||||
std::string GridCoord2D::to_string() const {
|
||||
return std::string("(" + std::to_string(_x_coord) + ", " +
|
||||
std::to_string(_y_coord) + ")");
|
||||
}
|
||||
|
||||
bool operator==(const GridCoord2D &lhs, const GridCoord2D &rhs) {
|
||||
return (lhs._x_coord == rhs._x_coord && lhs._y_coord == rhs._y_coord);
|
||||
}
|
||||
bool operator==(const GridCoord2D &lhs, const GridCoord2D &rhs) {
|
||||
return (lhs._x_coord == rhs._x_coord && lhs._y_coord == rhs._y_coord);
|
||||
}
|
||||
|
||||
bool operator!=(const GridCoord2D &lhs, const GridCoord2D &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
bool operator!=(const GridCoord2D &lhs, const GridCoord2D &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &lhs, const GridCoord2D &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
std::ostream &operator<<(std::ostream &lhs, const GridCoord2D &rhs) {
|
||||
return lhs << rhs.to_string();
|
||||
}
|
||||
|
||||
Grid2D::Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
|
||||
bool wrap_y) {
|
||||
_maximum_x = maximum_x;
|
||||
_maximum_y = maximum_y;
|
||||
_wrap_x = wrap_x;
|
||||
_wrap_y = wrap_y;
|
||||
Grid2D::Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
|
||||
bool wrap_y) {
|
||||
_maximum_x = maximum_x;
|
||||
_maximum_y = maximum_y;
|
||||
_wrap_x = wrap_x;
|
||||
_wrap_y = wrap_y;
|
||||
|
||||
_agent_grid = new std::vector<AgentID> *[_maximum_x];
|
||||
for (auto i = 0; i < _maximum_x; i++)
|
||||
_agent_grid[i] = new std::vector<AgentID>[_maximum_y];
|
||||
_agent_grid = new std::vector<AgentID> *[_maximum_x];
|
||||
for (auto i = 0; i < _maximum_x; i++)
|
||||
_agent_grid[i] = new std::vector<AgentID>[_maximum_y];
|
||||
|
||||
_agent_index = new std::map<AgentID, GridCoord2D>;
|
||||
}
|
||||
_agent_index = new std::map<AgentID, GridCoord2D>;
|
||||
}
|
||||
|
||||
Grid2D::~Grid2D(void) {
|
||||
delete _agent_index;
|
||||
Grid2D::~Grid2D() {
|
||||
delete _agent_index;
|
||||
|
||||
for (auto i = 0; i < _maximum_x; i++) delete[] _agent_grid[i];
|
||||
delete[] _agent_grid;
|
||||
}
|
||||
for (auto i = 0; i < _maximum_x; i++) delete[] _agent_grid[i];
|
||||
delete[] _agent_grid;
|
||||
}
|
||||
|
||||
bool Grid2D::delete_agent(AgentID agent_id) {
|
||||
auto location = get_location_by_agent(agent_id);
|
||||
[[maybe_unused]] bool Grid2D::delete_agent(AgentID agent_id) {
|
||||
auto coord = get_location_by_agent(agent_id);
|
||||
|
||||
return delete_agent(agent_id, location);
|
||||
}
|
||||
return delete_agent(agent_id, coord);
|
||||
}
|
||||
|
||||
bool Grid2D::delete_agent(AgentID agent_id, GridCoord2D location) {
|
||||
auto agent_list = _agent_grid[static_cast<int>(location.get_x_location())]
|
||||
[static_cast<int>(location.get_y_location())];
|
||||
for (auto test_agent_id = agent_list.begin();
|
||||
test_agent_id < agent_list.end(); test_agent_id++) {
|
||||
if (*test_agent_id == agent_id) {
|
||||
agent_list.erase(test_agent_id);
|
||||
_agent_index->erase(agent_id);
|
||||
return true;
|
||||
bool Grid2D::delete_agent(AgentID agent_id, const GridCoord2D &coord) {
|
||||
auto agent_list = _agent_grid[static_cast<int>(coord.get_x_location())][static_cast<int>(coord.get_y_location())];
|
||||
|
||||
for (auto test_agent_id = agent_list.begin();
|
||||
test_agent_id < agent_list.end(); test_agent_id++) {
|
||||
if (*test_agent_id == agent_id) {
|
||||
agent_list.erase(test_agent_id);
|
||||
_agent_index->erase(agent_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool Grid2D::is_location_valid(const GridCoord2D& coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
auto y = coord.get_y_location();
|
||||
|
||||
bool Grid2D::is_location_valid(GridCoord2D location) const {
|
||||
auto x = location.get_x_location();
|
||||
auto y = location.get_y_location();
|
||||
|
||||
return (x >= 0 && x < static_cast<int>(_maximum_x) && y >= 0 &&
|
||||
y < static_cast<int>(_maximum_y));
|
||||
}
|
||||
|
||||
GridCoord2D Grid2D::get_location_by_agent(AgentID agent_id) const {
|
||||
return _agent_index->at(agent_id);
|
||||
}
|
||||
|
||||
bool Grid2D::move_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
GridCoord2D current_location = get_location_by_agent(agent_id);
|
||||
|
||||
if (delete_agent(agent_id, current_location) == true)
|
||||
return add_agent(agent_id, coord);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Grid2D::get_wrap_x(void) const { return _wrap_x; }
|
||||
bool Grid2D::get_wrap_y(void) const { return _wrap_y; }
|
||||
|
||||
std::vector<GridCoord2D> Grid2D::get_neighborhood(
|
||||
AgentID agent_id, GridNeighborhoodType neighborhood_type,
|
||||
bool includeCenter) const {
|
||||
GridCoord2D location = get_location_by_agent(agent_id);
|
||||
|
||||
return get_neighborhood(location, neighborhood_type, includeCenter);
|
||||
}
|
||||
|
||||
std::vector<GridCoord2D> Grid2D::get_neighborhood(
|
||||
GridCoord2D location, GridNeighborhoodType neighborhood_type,
|
||||
bool include_center) const {
|
||||
std::vector<GridCoord2D> neighborhood;
|
||||
auto x = location.get_x_location();
|
||||
auto y = location.get_y_location();
|
||||
|
||||
// We assume our starting position is valid
|
||||
if (include_center) neighborhood.push_back(location);
|
||||
|
||||
// N, E, S, W
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x, y - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x, y + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
return (x >= 0 && x < static_cast<int>(_maximum_x) && y >= 0 &&
|
||||
y < static_cast<int>(_maximum_y));
|
||||
}
|
||||
|
||||
if (neighborhood_type == GridNeighborhoodType::Moore) {
|
||||
// NE, SE, SW, NW
|
||||
GridCoord2D Grid2D::get_location_by_agent(AgentID agent_id) const {
|
||||
return _agent_index->at(agent_id);
|
||||
}
|
||||
|
||||
bool Grid2D::move_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
GridCoord2D current_location = get_location_by_agent(agent_id);
|
||||
|
||||
if (delete_agent(agent_id, current_location))
|
||||
return add_agent(agent_id, std::move(coord));
|
||||
return false;
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool Grid2D::get_wrap_x() const { return _wrap_x; }
|
||||
[[maybe_unused]] bool Grid2D::get_wrap_y() const { return _wrap_y; }
|
||||
|
||||
std::vector<GridCoord2D> Grid2D::get_neighborhood(
|
||||
AgentID agent_id, GridNeighborhoodType neighborhood_type,
|
||||
bool includeCenter) const {
|
||||
GridCoord2D location = get_location_by_agent(agent_id);
|
||||
|
||||
return get_neighborhood(location, neighborhood_type, includeCenter);
|
||||
}
|
||||
|
||||
std::vector<GridCoord2D> Grid2D::get_neighborhood(const GridCoord2D& location, GridNeighborhoodType neighborhood_type, bool include_center) const {
|
||||
std::vector<GridCoord2D> neighborhood;
|
||||
auto x = location.get_x_location();
|
||||
auto y = location.get_y_location();
|
||||
|
||||
// We assume our starting position is valid
|
||||
if (include_center) neighborhood.push_back(location);
|
||||
|
||||
// N, E, S, W
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y - 1));
|
||||
auto new_location = coord_wrap(GridCoord2D(x, y - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y + 1));
|
||||
auto new_location = coord_wrap(GridCoord2D(x, y + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y + 1));
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y - 1));
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
|
||||
if (neighborhood_type == GridNeighborhoodType::Moore) {
|
||||
// NE, SE, SW, NW
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x + 1, y + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y + 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
{
|
||||
auto new_location = coord_wrap(GridCoord2D(x - 1, y - 1));
|
||||
if (is_location_valid(new_location))
|
||||
neighborhood.push_back(coord_wrap(new_location));
|
||||
}
|
||||
}
|
||||
|
||||
return neighborhood;
|
||||
}
|
||||
|
||||
return neighborhood;
|
||||
}
|
||||
std::vector<AgentID> *Grid2D::get_location_contents(const GridCoord2D& coord) const {
|
||||
if (is_location_valid(coord) && !is_location_empty(coord))
|
||||
return &_agent_grid[coord.get_x_location()][coord.get_y_location()];
|
||||
|
||||
std::vector<AgentID> *Grid2D::get_location_contents(
|
||||
GridCoord2D location) const {
|
||||
if (is_location_valid(location) && !is_location_empty(location)) {
|
||||
return &_agent_grid[location.get_x_location()]
|
||||
[location.get_y_location()];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
[[maybe_unused]] unsigned int Grid2D::get_maximum_x() const { return _maximum_x; }
|
||||
[[maybe_unused]] unsigned int Grid2D::get_maximum_y() const { return _maximum_y; }
|
||||
|
||||
unsigned int Grid2D::get_maximum_x(void) const { return _maximum_x; }
|
||||
unsigned int Grid2D::get_maximum_y(void) const { return _maximum_y; }
|
||||
GridCoord2D Grid2D::coord_wrap(const GridCoord2D& coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
auto y = coord.get_y_location();
|
||||
|
||||
GridCoord2D Grid2D::coord_wrap(GridCoord2D location) const {
|
||||
auto x = location.get_x_location();
|
||||
auto y = location.get_y_location();
|
||||
if (_wrap_x)
|
||||
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
|
||||
if (_wrap_x)
|
||||
y = (y + static_cast<int>(_maximum_y)) % static_cast<int>(_maximum_y);
|
||||
return {x, y};
|
||||
}
|
||||
|
||||
if (_wrap_x)
|
||||
x = (x + static_cast<int>(_maximum_x)) % static_cast<int>(_maximum_x);
|
||||
if (_wrap_x)
|
||||
y = (y + static_cast<int>(_maximum_y)) % static_cast<int>(_maximum_y);
|
||||
return GridCoord2D(x, y);
|
||||
}
|
||||
bool Grid2D::is_location_empty(const GridCoord2D& coord) const {
|
||||
auto x = coord.get_x_location();
|
||||
auto y = coord.get_y_location();
|
||||
|
||||
bool Grid2D::is_location_empty(GridCoord2D location) const {
|
||||
auto x = location.get_x_location();
|
||||
auto y = location.get_y_location();
|
||||
|
||||
return _agent_grid[x][y].size() == 0;
|
||||
}
|
||||
return _agent_grid[x][y].empty();
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -25,21 +25,19 @@
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid1d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/multigrid1d.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
bool MultiGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
if (is_location_valid(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()].push_back(agent_id);
|
||||
return (true);
|
||||
bool MultiGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
if (is_location_valid(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()].push_back(agent_id);
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -25,26 +25,20 @@
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid2d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/multigrid2d.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
MultiGrid2D::MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y,
|
||||
bool wrap_x, bool wrap_y)
|
||||
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {}
|
||||
bool MultiGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
if (is_location_valid(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
|
||||
agent_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MultiGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
if (is_location_valid(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
|
||||
agent_id);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -23,35 +23,29 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/model.h>
|
||||
#include <kami/random.h>
|
||||
#include <kami/scheduler.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <kami/model.h>
|
||||
#include <kami/random.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
RandomScheduler::RandomScheduler(Model *model) : SequentialScheduler(model) {}
|
||||
RandomScheduler::RandomScheduler(Model *model, std::shared_ptr<std::mt19937> rng)
|
||||
: SequentialScheduler(model) {
|
||||
this->set_rng(std::move(rng));
|
||||
}
|
||||
|
||||
RandomScheduler::RandomScheduler(Model *model,
|
||||
std::shared_ptr<std::mt19937> rng)
|
||||
: SequentialScheduler(model) {
|
||||
this->set_rng(rng);
|
||||
}
|
||||
void RandomScheduler::step() {
|
||||
shuffle(_agent_list.begin(), _agent_list.end(), *_rng);
|
||||
this->SequentialScheduler::step();
|
||||
}
|
||||
|
||||
void RandomScheduler::step() {
|
||||
shuffle(_agent_list.begin(), _agent_list.end(), *_rng);
|
||||
this->SequentialScheduler::step();
|
||||
}
|
||||
void RandomScheduler::set_rng(std::shared_ptr<std::mt19937> rng) {
|
||||
this->_rng = std::move(rng);
|
||||
}
|
||||
|
||||
void RandomScheduler::set_rng(std::shared_ptr<std::mt19937> rng) {
|
||||
this->_rng = rng;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::mt19937> RandomScheduler::get_rng() { return (_rng); }
|
||||
[[maybe_unused]] std::shared_ptr<std::mt19937> RandomScheduler::get_rng() { return (_rng); }
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -23,42 +23,37 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/model.h>
|
||||
#include <kami/scheduler.h>
|
||||
#include <kami/sequential.h>
|
||||
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
namespace kami {
|
||||
|
||||
SequentialScheduler::SequentialScheduler(Model *model) {
|
||||
_step_counter = 0;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
void SequentialScheduler::add_agent(AgentID agent_id) {
|
||||
_agent_list.push_back(agent_id);
|
||||
}
|
||||
|
||||
void SequentialScheduler::delete_agent(AgentID agent_id) {
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++)
|
||||
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
|
||||
return;
|
||||
|
||||
// ERROR HERE
|
||||
}
|
||||
|
||||
void SequentialScheduler::step() {
|
||||
_step_counter++;
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
Agent *agent = _model->get_agent_by_id(*agent_list_iter);
|
||||
if (agent != nullptr) agent->step();
|
||||
SequentialScheduler::SequentialScheduler(Model *model) {
|
||||
_step_counter = 0;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
void SequentialScheduler::add_agent(AgentID agent_id) {
|
||||
_agent_list.push_back(agent_id);
|
||||
}
|
||||
|
||||
void SequentialScheduler::delete_agent(AgentID agent_id) {
|
||||
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++)
|
||||
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
|
||||
// ERROR HERE
|
||||
}
|
||||
|
||||
void SequentialScheduler::step() {
|
||||
_step_counter++;
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
Agent *agent = _model->get_agent_by_id(*agent_list_iter);
|
||||
if (agent != nullptr) agent->step();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -24,22 +24,18 @@
|
||||
*/
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid1d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/sologrid1d.h>
|
||||
|
||||
namespace kami {
|
||||
|
||||
bool SoloGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
if (is_location_valid(coord) & is_location_empty(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()].push_back(agent_id);
|
||||
return true;
|
||||
bool SoloGrid1D::add_agent(AgentID agent_id, GridCoord1D coord) {
|
||||
if (is_location_valid(coord) & is_location_empty(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord1D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()].push_back(agent_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -24,29 +24,20 @@
|
||||
*/
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/domain.h>
|
||||
#include <kami/grid.h>
|
||||
#include <kami/grid2d.h>
|
||||
#include <kami/kami.h>
|
||||
#include <kami/sologrid2d.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace kami {
|
||||
|
||||
SoloGrid2D::SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y,
|
||||
bool wrap_x, bool wrap_y)
|
||||
: Grid2D(maximum_x, maximum_y, wrap_x, wrap_y) {}
|
||||
bool SoloGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
if (is_location_valid(coord) & is_location_empty(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(agent_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoloGrid2D::add_agent(AgentID agent_id, GridCoord2D coord) {
|
||||
if (is_location_valid(coord) & is_location_empty(coord)) {
|
||||
_agent_index->insert(std::pair<AgentID, GridCoord2D>(agent_id, coord));
|
||||
_agent_grid[coord.get_x_location()][coord.get_y_location()].push_back(
|
||||
agent_id);
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -23,55 +23,40 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/model.h>
|
||||
#include <kami/scheduler.h>
|
||||
#include <kami/sequential.h>
|
||||
#include <kami/staged.h>
|
||||
|
||||
#include <random>
|
||||
#include <string>
|
||||
|
||||
namespace kami {
|
||||
|
||||
StagedScheduler::StagedScheduler(Model *model) {
|
||||
_step_counter = 0;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
StagedScheduler::~StagedScheduler() {}
|
||||
|
||||
void StagedScheduler::add_agent(AgentID agent_id) {
|
||||
_agent_list.push_back(agent_id);
|
||||
}
|
||||
|
||||
void StagedScheduler::delete_agent(AgentID agent_id) {
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++)
|
||||
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
|
||||
return;
|
||||
}
|
||||
|
||||
void StagedScheduler::step() {
|
||||
_step_counter++;
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
StagedAgent *agent = dynamic_cast<StagedAgent *>(
|
||||
_model->get_agent_by_id(*agent_list_iter));
|
||||
if (agent != nullptr) agent->step();
|
||||
// ERROR HERE
|
||||
StagedScheduler::StagedScheduler(Model *model) {
|
||||
_step_counter = 0;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin();
|
||||
agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
StagedAgent *agent = dynamic_cast<StagedAgent *>(
|
||||
_model->get_agent_by_id(*agent_list_iter));
|
||||
if (agent != nullptr) agent->advance();
|
||||
// ERROR HERE
|
||||
void StagedScheduler::add_agent(AgentID agent_id) {
|
||||
_agent_list.push_back(agent_id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
void StagedScheduler::delete_agent(AgentID agent_id) {
|
||||
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++)
|
||||
if (*agent_list_iter == agent_id) _agent_list.erase(agent_list_iter);
|
||||
}
|
||||
|
||||
void StagedScheduler::step() {
|
||||
_step_counter++;
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
auto *agent = dynamic_cast<StagedAgent *>(_model->get_agent_by_id(*agent_list_iter));
|
||||
if (agent != nullptr) agent->step();
|
||||
}
|
||||
|
||||
for (auto agent_list_iter = _agent_list.begin(); agent_list_iter < _agent_list.end(); agent_list_iter++) {
|
||||
auto *agent = dynamic_cast<StagedAgent *>(_model->get_agent_by_id(*agent_list_iter));
|
||||
if (agent != nullptr) agent->advance();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kami
|
||||
|
||||
@@ -1,22 +1,45 @@
|
||||
/*-
|
||||
* TODO FILEHEADER
|
||||
* Copyright (c) 2020 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 <string>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/config.h>
|
||||
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <CLI/Config.hpp>
|
||||
#include <CLI/Formatter.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace kami;
|
||||
using namespace std;
|
||||
|
||||
class TestAgent : public Agent {
|
||||
void step(){};
|
||||
void step() override {};
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -25,15 +48,12 @@ int main(int argc, char **argv) {
|
||||
auto console = spdlog::stdout_color_st(ident);
|
||||
string logLevelOption = "info";
|
||||
|
||||
app.add_option("-l", logLevelOption, "Set the logging level")
|
||||
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
|
||||
app.add_option("-l", logLevelOption, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
console->set_level(spdlog::level::from_str(logLevelOption));
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING,
|
||||
logLevelOption);
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, logLevelOption);
|
||||
|
||||
TestAgent test_agent;
|
||||
console->debug("Successfully created Agent with ID {}",
|
||||
test_agent.get_agent_id().to_string());
|
||||
console->debug("Successfully created Agent with ID {}", test_agent.get_agent_id().to_string());
|
||||
}
|
||||
|
||||
@@ -1,16 +1,39 @@
|
||||
/*-
|
||||
* TODO FILEHEADER
|
||||
* Copyright (c) 2020 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 <string>
|
||||
|
||||
#include <kami/agent.h>
|
||||
#include <kami/config.h>
|
||||
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <CLI/App.hpp>
|
||||
#include <CLI/Config.hpp>
|
||||
#include <CLI/Formatter.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace kami;
|
||||
using namespace std;
|
||||
@@ -21,15 +44,12 @@ int main(int argc, char **argv) {
|
||||
auto console = spdlog::stdout_color_st(ident);
|
||||
string logLevelOption = "info";
|
||||
|
||||
app.add_option("-l", logLevelOption, "Set the logging level")
|
||||
->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
|
||||
app.add_option("-l", logLevelOption, "Set the logging level")->check(CLI::IsMember(SPDLOG_LEVEL_NAMES));
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
console->set_level(spdlog::level::from_str(logLevelOption));
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING,
|
||||
logLevelOption);
|
||||
console->info("Compiled with Kami/{}, log level {}", KAMI_VERSION_STRING, logLevelOption);
|
||||
|
||||
AgentID testAgentID;
|
||||
console->debug("Successfully created AgentID with ID {}",
|
||||
testAgentID.to_string());
|
||||
console->debug("Successfully created AgentID with ID {}", testAgentID.to_string());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user