Separate all method declarations from definitions

This commit is contained in:
James P. Howard, II
2022-09-02 07:50:16 -04:00
parent a08b316b96
commit 445e10252e
23 changed files with 169 additions and 88 deletions

View File

@@ -30,6 +30,8 @@
#include <memory>
#include <random>
#include <cassert>
#include <CLI/CLI.hpp>
#include <spdlog/sinks/stdout_color_sinks.h>

View File

@@ -64,14 +64,14 @@ namespace kami {
/**
* @brief Constructs a new unique identifier.
*/
AgentID() : _id(_id_next++) {};
AgentID();
/**
* @brief 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); }
[[nodiscard]] std::string to_string() const;
/**
* @brief Test if two `AgentID` instances are equal.

View File

@@ -51,7 +51,7 @@ namespace kami {
/**
* @brief Constructor for one-dimensional coordinates
*/
explicit GridCoord1D(int x_coord) : _x_coord(x_coord){};
explicit GridCoord1D(int x_coord);;
/**
* @brief Return the `x` coordinate
@@ -102,6 +102,32 @@ namespace kami {
*/
friend std::ostream &operator<<(std::ostream &lhs, const GridCoord1D &rhs);
/**
* @brief Add two coordinates together
*/
inline friend GridCoord1D operator+(const GridCoord1D &lhs, const GridCoord1D &rhs);
/**
* @brief Subtract one coordinate from another
*/
inline friend GridCoord1D operator-(const GridCoord1D &lhs, const GridCoord1D &rhs);
/**
* @brief Multiply a coordinate by a scalar
*
* @details If any component of the resulting value is not a whole number, it is
* truncated following the same rules as `int`.
*/
inline friend GridCoord1D operator*(const GridCoord1D &lhs, const double rhs);
/**
* @brief Multiply a coordinate by a scalar
*
* @details If any component of the resulting value is not a whole number, it is
* truncated following the same rules as `int`.
*/
inline friend GridCoord1D operator*(const double lhs, const GridCoord1D &rhs);
private:
int _x_coord;
};

View File

@@ -49,25 +49,11 @@ namespace kami {
* @brief Two-dimensional coordinates
*/
class LIBKAMI_EXPORT GridCoord2D : public GridCoord {
protected:
inline double distance_chebyshev(std::shared_ptr<GridCoord2D> &p) const {
return static_cast<double>(fmax(abs(_x_coord - p->_x_coord), abs(_x_coord - p->_x_coord)));
};
inline double distance_euclidean(std::shared_ptr<GridCoord2D> &p) const {
return sqrt(pow(_x_coord - p->_x_coord, 2) + pow(_x_coord - p->_x_coord, 2));
};
inline double distance_manhattan(std::shared_ptr<GridCoord2D> &p) const {
return static_cast<double>(abs(_x_coord - p->_x_coord) + abs(_x_coord - p->_x_coord));
};
public:
/**
* @brief Constructor for two-dimensional coordinates
*/
GridCoord2D(int x_coord, int y_coord)
: _x_coord(x_coord), _y_coord(y_coord) {};
GridCoord2D(int x_coord, int y_coord);;
/**
* @brief Get the coordinate in the first dimension or `x`.
@@ -123,16 +109,12 @@ namespace kami {
/**
* @brief Add two coordinates together
*/
inline friend GridCoord2D operator+(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return {lhs._x_coord + rhs._x_coord, lhs._y_coord + rhs._y_coord};
}
inline friend GridCoord2D operator+(const GridCoord2D &lhs, const GridCoord2D &rhs);
/**
* @brief Subtract one coordinate from another
*/
inline friend GridCoord2D operator-(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return {lhs._x_coord - rhs._x_coord, lhs._y_coord - rhs._y_coord};
}
inline friend GridCoord2D operator-(const GridCoord2D &lhs, const GridCoord2D &rhs);
/**
* @brief Multiply a coordinate by a scalar
@@ -140,9 +122,7 @@ namespace kami {
* @details If any component of the resulting value is not a whole number, it is
* truncated following the same rules as `int`.
*/
inline friend GridCoord2D operator*(const GridCoord2D &lhs, const double rhs) {
return {static_cast<int>(lhs._x_coord * rhs), static_cast<int>(lhs._y_coord * rhs)};
}
inline friend GridCoord2D operator*(const GridCoord2D &lhs, const double rhs);
/**
* @brief Multiply a coordinate by a scalar
@@ -150,9 +130,14 @@ namespace kami {
* @details If any component of the resulting value is not a whole number, it is
* truncated following the same rules as `int`.
*/
inline friend GridCoord2D operator*(const double lhs, const GridCoord2D &rhs) {
return {static_cast<int>(rhs._x_coord * lhs), static_cast<int>(rhs._y_coord * lhs)};
}
inline friend GridCoord2D operator*(const double lhs, const GridCoord2D &rhs);
protected:
inline double distance_chebyshev(std::shared_ptr<GridCoord2D> &p) const;
inline double distance_euclidean(std::shared_ptr<GridCoord2D> &p) const;
inline double distance_manhattan(std::shared_ptr<GridCoord2D> &p) const;
private:
int _x_coord, _y_coord;

View File

@@ -1,5 +1,5 @@
/*-
* Copyright (c) 2020 The Johns Hopkins University Applied Physics
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person

View File

@@ -53,8 +53,7 @@ namespace kami {
* @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) {}
MultiGrid1D(unsigned int maximum_x, bool wrap_x);
/**
* @brief Place agent on the grid at the specified location.

View File

@@ -57,8 +57,7 @@ namespace kami {
* @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) {};
MultiGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y);
/**
* @brief Place agent on the grid at the specified location.

View File

@@ -41,17 +41,6 @@ namespace kami {
* @brief An abstract for generic models
*/
class LIBKAMI_EXPORT Population {
protected:
/**
* @brief A mapping of `AgentID` to `Agent` pointers
*
* @details This is the mapping of all `AgentID`s to
* pointers to the corresponding `Agent` in this population.
* This is left exposed as protected should any subclass
* wish to manipulate this mapping directly.
*/
std::map<kami::AgentID, std::shared_ptr<Agent>> _agent_map;
public:
/**
* @brief Get a reference to an `Agent` by `AgentID`
@@ -86,6 +75,17 @@ namespace kami {
* @returns a `std::vector` of all the `AgentID`'s in the `Population`
*/
[[nodiscard]] std::unique_ptr<std::vector<AgentID>> get_agent_list() const;
protected:
/**
* @brief A mapping of `AgentID` to `Agent` pointers
*
* @details This is the mapping of all `AgentID`s to
* pointers to the corresponding `Agent` in this population.
* This is left exposed as protected should any subclass
* wish to manipulate this mapping directly.
*/
std::map<kami::AgentID, std::shared_ptr<Agent>> _agent_map;
};
} // namespace kami

View File

@@ -48,9 +48,6 @@ namespace kami {
* but is not guaranteed not to repeat.
*/
class LIBKAMI_EXPORT RandomScheduler : public SequentialScheduler, std::enable_shared_from_this<RandomScheduler> {
private:
std::shared_ptr<std::mt19937> _rng = nullptr;
public:
/**
* @brief Constructor.
@@ -102,6 +99,10 @@ namespace kami {
* the order of agent stepping.
*/
std::shared_ptr<std::mt19937> get_rng();
private:
std::shared_ptr<std::mt19937> _rng = nullptr;
};
} // namespace kami

View File

@@ -79,9 +79,7 @@ namespace kami {
private:
// This should be uncallable, but knocks out the inherited method.
AgentID step(std::shared_ptr<Model> model) override {
return get_agent_id();
};
AgentID step(std::shared_ptr<Model> model) override;;
int _step_counter = 0;
};
@@ -113,9 +111,7 @@ namespace kami {
* @details The step_id should probably be a monotonically
* incrementing integer.
*/
inline virtual unsigned int get_step_id() {
return _step_count;
};
virtual unsigned int get_step_id();
/**
* @brief Execute a single time step of the model

View File

@@ -46,12 +46,6 @@ namespace kami {
* the step function for each agent based on the type of scheduling implemented.
*/
class LIBKAMI_EXPORT Scheduler {
protected:
/**
* Counter to increment on each step
*/
int _step_counter = 0;
public:
/**
* @brief Execute a single time step.
@@ -87,6 +81,12 @@ namespace kami {
virtual std::optional<std::unique_ptr<std::vector<AgentID>>>
step(std::shared_ptr<ReporterModel> model, std::unique_ptr<std::vector<AgentID>> agent_list) = 0;
protected:
/**
* Counter to increment on each step
*/
int _step_counter = 0;
};
} // namespace kami

View File

@@ -52,8 +52,7 @@ namespace kami {
* @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) {}
SoloGrid1D(unsigned int maximum_x, bool wrap_x);
/**
* @brief Place agent on the grid at the specified location.

View File

@@ -54,8 +54,7 @@ namespace kami {
* @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) {};
SoloGrid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x, bool wrap_y);;
/**
* @details Place agent on the grid at the specified location.

View File

@@ -48,6 +48,26 @@ namespace kami {
* `delete_agent()`.
*/
class LIBKAMI_EXPORT StagedScheduler : public SequentialScheduler {
public:
/**
* @brief Execute a single time step
*
* @details 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.
*
* @param model a reference copy of the model
* @param agent_list list of agents to execute the step
*
* @returns returns vector of agents successfully stepped
*/
std::optional<std::unique_ptr<std::vector<AgentID>>>
step(std::shared_ptr<Model> model, std::unique_ptr<std::vector<AgentID>> agent_list) override;
std::optional<std::unique_ptr<std::vector<AgentID>>>
step(std::shared_ptr<ReporterModel> model, std::unique_ptr<std::vector<AgentID>> agent_list) override;
private:
/**
* @brief Advance a single time step.
@@ -83,26 +103,6 @@ namespace kami {
std::optional<std::unique_ptr<std::vector<AgentID>>>
advance(std::shared_ptr<ReporterModel> model, std::unique_ptr<std::vector<AgentID>> agent_list);
public:
/**
* @brief Execute a single time step
*
* @details 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.
*
* @param model a reference copy of the model
* @param agent_list list of agents to execute the step
*
* @returns returns vector of agents successfully stepped
*/
std::optional<std::unique_ptr<std::vector<AgentID>>>
step(std::shared_ptr<Model> model, std::unique_ptr<std::vector<AgentID>> agent_list) override;
std::optional<std::unique_ptr<std::vector<AgentID>>>
step(std::shared_ptr<ReporterModel> model, std::unique_ptr<std::vector<AgentID>> agent_list) override;
};
} // namespace kami

View File

@@ -23,13 +23,17 @@
* SOFTWARE.
*/
#include <kami/agent.h>
#include <iostream>
#include <string>
#include <kami/agent.h>
namespace kami {
AgentID::AgentID() : _id(_id_next++) {}
std::string AgentID::to_string() const { return std::to_string(_id); }
bool operator==(const AgentID &lhs, const AgentID &rhs) {
return lhs._id == rhs._id;
}

View File

@@ -37,6 +37,8 @@
namespace kami {
GridCoord1D::GridCoord1D(int x_coord) : _x_coord(x_coord) {}
int GridCoord1D::get_x_location() const {
return _x_coord;
}
@@ -65,6 +67,23 @@ namespace kami {
return lhs << rhs.to_string();
}
GridCoord1D operator+(const GridCoord1D &lhs, const GridCoord1D &rhs) {
return GridCoord1D(lhs._x_coord + rhs._x_coord);
}
GridCoord1D operator-(const GridCoord1D &lhs, const GridCoord1D &rhs) {
return GridCoord1D(lhs._x_coord - rhs._x_coord);
}
GridCoord1D operator*(const GridCoord1D &lhs, const double rhs) {
return GridCoord1D(static_cast<int>(lhs._x_coord * rhs));
}
GridCoord1D operator*(const double lhs, const GridCoord1D &rhs) {
return GridCoord1D(static_cast<int>(rhs._x_coord * lhs));
}
Grid1D::Grid1D(unsigned int maximum_x, bool wrap_x) {
_maximum_x = maximum_x;
_wrap_x = wrap_x;

View File

@@ -74,6 +74,37 @@ namespace kami {
return lhs << rhs.to_string();
}
GridCoord2D::GridCoord2D(int x_coord, int y_coord)
: _x_coord(x_coord), _y_coord(y_coord) {}
double GridCoord2D::distance_chebyshev(std::shared_ptr<GridCoord2D> &p) const {
return static_cast<double>(fmax(abs(_x_coord - p->_x_coord), abs(_x_coord - p->_x_coord)));
}
double GridCoord2D::distance_euclidean(std::shared_ptr<GridCoord2D> &p) const {
return sqrt(pow(_x_coord - p->_x_coord, 2) + pow(_x_coord - p->_x_coord, 2));
}
double GridCoord2D::distance_manhattan(std::shared_ptr<GridCoord2D> &p) const {
return static_cast<double>(abs(_x_coord - p->_x_coord) + abs(_x_coord - p->_x_coord));
}
GridCoord2D operator+(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return {lhs._x_coord + rhs._x_coord, lhs._y_coord + rhs._y_coord};
}
GridCoord2D operator-(const GridCoord2D &lhs, const GridCoord2D &rhs) {
return {lhs._x_coord - rhs._x_coord, lhs._y_coord - rhs._y_coord};
}
GridCoord2D operator*(const GridCoord2D &lhs, const double rhs) {
return {static_cast<int>(lhs._x_coord * rhs), static_cast<int>(lhs._y_coord * rhs)};
}
GridCoord2D operator*(const double lhs, const GridCoord2D &rhs) {
return {static_cast<int>(rhs._x_coord * lhs), static_cast<int>(rhs._y_coord * lhs)};
}
Grid2D::Grid2D(unsigned int maximum_x, unsigned int maximum_y, bool wrap_x,
bool wrap_y) {
_maximum_x = maximum_x;

View File

@@ -1,5 +1,5 @@
/*-
* Copyright (c) 2020 The Johns Hopkins University Applied Physics
* Copyright (c) 2022 The Johns Hopkins University Applied Physics
* Laboratory LLC
*
* Permission is hereby granted, free of charge, to any person

View File

@@ -30,6 +30,9 @@
namespace kami {
MultiGrid1D::MultiGrid1D(unsigned int maximum_x, bool wrap_x)
: Grid1D(maximum_x, wrap_x) {}
std::optional<AgentID> MultiGrid1D::add_agent(const AgentID agent_id, const GridCoord1D &coord) {
if (!is_location_valid(coord))
return std::nullopt;

View File

@@ -30,6 +30,9 @@
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) {}
std::optional<AgentID> MultiGrid2D::add_agent(const AgentID agent_id, const GridCoord2D &coord) {
if (!is_location_valid(coord))
return std::nullopt;

View File

@@ -54,6 +54,10 @@ namespace kami {
return std::move(_rpt->report(std::static_pointer_cast<ReporterModel>(shared_from_this())));
}
inline unsigned int ReporterModel::get_step_id() {
return _step_count;
}
Reporter::Reporter() {
_report_data = std::make_unique<std::vector<nlohmann::json>>();
}
@@ -116,4 +120,9 @@ namespace kami {
return std::move(json_data);
}
AgentID ReporterAgent::step(std::shared_ptr<Model> model) {
return get_agent_id();
}
} // namespace kami

View File

@@ -28,6 +28,9 @@
namespace kami {
SoloGrid1D::SoloGrid1D(unsigned int maximum_x, bool wrap_x)
: Grid1D(maximum_x, wrap_x) {}
std::optional<AgentID> SoloGrid1D::add_agent(const AgentID agent_id, const GridCoord1D &coord) {
if (!is_location_valid(coord))
return std::nullopt;

View File

@@ -30,6 +30,9 @@
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) {}
std::optional<AgentID> SoloGrid2D::add_agent(const AgentID agent_id, const GridCoord2D &coord) {
if (!is_location_valid(coord))
return std::nullopt;