31 Commits
0.3.0 ... 0.4.1

Author SHA1 Message Date
James P. Howard, II
01d8154017 Merge branch 'hotfix/0.4.1' 2021-09-25 20:52:45 -04:00
James P. Howard, II
c145466758 Added support for README links 2021-09-25 20:52:37 -04:00
James P. Howard, II
d7cd7bcfc4 Merge branch 'release/0.4.0' 2021-09-25 19:39:02 -04:00
James P. Howard, II
98959520ea Bump version to 0.4.0 2021-09-25 19:38:49 -04:00
James P. Howard, II
42c87ccccd Merge branch 'hotfix/0.3.1' into develop 2021-09-25 19:34:08 -04:00
James P. Howard, II
ba0ae24cfc Merge branch 'hotfix/0.3.1' 2021-09-25 19:33:57 -04:00
James P. Howard, II
e2c825e2e6 Version bump to 0.3.1 2021-09-25 19:33:51 -04:00
James P. Howard, II
c7f4c706cd Separate build workflows for CI 2021-09-25 19:28:46 -04:00
James P. Howard, II
584c2b94d8 The CLion linter is a beast 2021-09-25 12:35:45 -04:00
James P. Howard, II
b02efaae07 Added missing copyrights 2021-09-24 13:58:20 -04:00
James P. Howard, II
087bdadc16 Updated changelog 2021-09-23 22:09:41 -04:00
James P. Howard, II
2027ff05eb Reworked Overview and TOC 2021-09-23 15:38:00 -04:00
James P. Howard, II
15647b905f Added the index to the TOC 2021-09-23 13:48:23 -04:00
James P. Howard, II
f0ce59c967 Pull out the links into a more native RST format 2021-09-23 13:46:20 -04:00
James P. Howard, II
7af69815f3 Not Markdown 2021-09-23 13:42:40 -04:00
James P. Howard, II
25febcb094 Fleshed out introduction text 2021-09-23 13:40:26 -04:00
James P. Howard, II
52bb8bb900 Finished requirements section 2021-09-21 21:26:09 -04:00
James P. Howard, II
f3f2b00740 Move releases to released version 2021-09-21 21:16:21 -04:00
James P. Howard, II
1200fb4de0 Added blank like to support changelog processing on RTD 2021-09-21 21:13:00 -04:00
James P. Howard, II
fb5d222915 Rebuild the changelog management process 2021-09-21 20:59:48 -04:00
James P. Howard, II
30fdd46d93 Start installation instructions in Markdown 2021-09-21 20:58:47 -04:00
James P. Howard, II
f474d6feff Add documentation for kami::RandomScheduler 2021-09-21 20:10:40 -04:00
James P. Howard, II
caf6d01b58 Add a changelog link 2021-09-20 21:25:20 -04:00
James P. Howard, II
44c541a4f8 Add a changelog 2021-09-20 21:17:09 -04:00
James P. Howard, II
0edd940344 Removing conancenter badge until ready to go on conancenter 2021-09-20 11:33:45 -04:00
James P. Howard, II
10f33b5f61 Add license information badges 2021-09-20 11:17:45 -04:00
James P. Howard, II
b6406b86d8 There's still a broken reference to SPDLOG here 2021-09-20 11:07:31 -04:00
James P. Howard, II
54f49a732c Add installation directions 2021-09-20 11:03:41 -04:00
James P. Howard, II
f2601ea85f Anchors aweigh! I really need to learn restructured text. 2021-09-20 10:58:17 -04:00
James P. Howard, II
b9c7f9b605 Remove alt text and add test badge 2021-09-20 10:43:19 -04:00
James P. Howard, II
d13960da35 Corrections to index badges 2021-09-20 10:37:44 -04:00
43 changed files with 1523 additions and 1495 deletions

View File

@@ -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
View 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}}

View File

@@ -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})
################################################################################

View File

@@ -1,8 +1,8 @@
[![Build status (main)](https://github.com/JHUAPL/kami/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/JHUAPL/kami/actions/workflows/build.yml)
[![Build status (develop)](https://github.com/JHUAPL/kami/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/JHUAPL/kami/actions/workflows/build.yml)
[![Build (main)](https://github.com/JHUAPL/kami/actions/workflows/build-main.yml/badge.svg)](https://github.com/JHUAPL/kami/actions/workflows/build-main.yml)
[![Build (develop)](https://github.com/JHUAPL/kami/actions/workflows/build-develop.yml/badge.svg)](https://github.com/JHUAPL/kami/actions/workflows/build-develop.yml)
[![Documentation status](https://readthedocs.org/projects/kami/badge/?version=latest)](https://kami.readthedocs.io/en/latest/?badge=latest)
[![Release status](https://img.shields.io/github/release/JHUAPL/kami.svg)](https://github.com/JHUAPL/kami/releases/latest)
[![ConanCenter status](https://repology.org/badge/version-for-repo/conancenter/kami.svg)](https://repology.org/project/kami/versions)
[![Release status](https://img.shields.io/github/release/JHUAPL/kami.svg)](https://kami.readthedocs.io/en/latest/?badge=latest)
![License](https://img.shields.io/github/license/JHUAPL/kami)
# Kami is Agent-Based Modeling in Modern C++

View File

@@ -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
View 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::

View File

@@ -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']

View File

@@ -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
View 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

View File

@@ -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
View 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::

View File

@@ -4,3 +4,5 @@ exhale
documenteer
myst-parser
sphinx_bootstrap_theme
sphinx_rtd_theme
releases

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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());
}

View File

@@ -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());
}