Initial import

This commit is contained in:
James P. Howard, II
2020-09-19 17:30:42 -04:00
parent 0bf74891a8
commit 37558713bf
25 changed files with 842 additions and 138 deletions

View File

@@ -6,13 +6,18 @@
# For many purposes, you may not need to change anything about this file. # For many purposes, you may not need to change anything about this file.
cmake_minimum_required(VERSION 3.8.2) cmake_minimum_required(VERSION 3.8.2)
project("KAMI" CXX)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
# Set project name, version and laguages here. (change as needed) # Set project name, version and laguages here. (change as needed)
# Version numbers are available by including "exampleConfig.h" in # Version numbers are available by including "exampleConfig.h" in
# the source. See exampleConfig.h.in for some more details. # the source. See exampleConfig.h.in for some more details.
project(CPP_BOILERPLATE VERSION 1.2.3.4 LANGUAGES CXX) project(CPP_BOILERPLATE VERSION 1.2.3.4 LANGUAGES CXX)
# Options: Things you can set via commandline options to cmake (e.g. -DENABLE_LTO=[ON|OFF]) # Options: Things you can set via commandline options to cmake (e.g. -DENABLE_LTO=[ON|OFF])
option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines. option(ENABLE_WARNINGS_SETTINGS "Allow target_set_warnings to add flags and defines.
Set this to OFF if you want to provide your own warning parameters." ON) Set this to OFF if you want to provide your own warning parameters." ON)
@@ -38,12 +43,15 @@ find_lto(CXX)
# Locate files (change as needed). # Locate files (change as needed).
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
set(SOURCES # All .cpp files in src/ set(SOURCES # All .cpp files in src/
src/example.cpp src/agent.cpp
src/kami.cpp
src/multigrid2d.cpp
src/random.cpp
) )
set(TESTFILES # All .cpp files in tests/ set(TESTFILES # All .cpp files in tests/
tests/main.cpp tests/dummy.cpp
) )
set(LIBRARY_NAME engine) # Default name for the library built from src/*.cpp (change if you wish) set(LIBRARY_NAME kami) # Default name for the library built from src/*.cpp (change if you wish)
# -------------------------------------------------------------------------------- # --------------------------------------------------------------------------------
# Build! (Change as needed) # Build! (Change as needed)
@@ -55,7 +63,7 @@ add_library(${LIBRARY_NAME} OBJECT ${SOURCES})
target_include_directories(${LIBRARY_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include) target_include_directories(${LIBRARY_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include)
# There's also (probably) doctests within the library, so we need to see this as well. # There's also (probably) doctests within the library, so we need to see this as well.
target_link_libraries(${LIBRARY_NAME} PUBLIC doctest) target_link_libraries(${LIBRARY_NAME} PUBLIC spdlog)
# Set the compile options you want (change as needed). # Set the compile options you want (change as needed).
target_set_warnings(${LIBRARY_NAME} ENABLE ALL AS_ERROR ALL DISABLE Annoying) target_set_warnings(${LIBRARY_NAME} ENABLE ALL AS_ERROR ALL DISABLE Annoying)
@@ -63,16 +71,16 @@ target_set_warnings(${LIBRARY_NAME} ENABLE ALL AS_ERROR ALL DISABLE Annoying)
# Add an executable for the file app/main.cpp. # Add an executable for the file app/main.cpp.
# If you add more executables, copy these lines accordingly. # If you add more executables, copy these lines accordingly.
add_executable(main app/main.cpp) # Name of exec. and location of file. add_executable(boltzmann examples/boltzmann.cpp) # Name of exec. and location of file.
target_link_libraries(main PRIVATE ${LIBRARY_NAME}) # Link the executable to library (if it uses it). target_link_libraries(boltzmann PRIVATE ${LIBRARY_NAME}) # Link the executable to library (if it uses it).
target_set_warnings(main ENABLE ALL AS_ERROR ALL DISABLE Annoying) # Set warnings (if needed). target_set_warnings(boltzmann ENABLE ALL AS_ERROR ALL DISABLE Annoying) # Set warnings (if needed).
target_enable_lto(main optimized) # enable link-time-optimization if available for non-debug configurations target_enable_lto(boltzmann optimized) # enable link-time-optimization if available for non-debug configurations
# Set the properties you require, e.g. what C++ standard to use. Here applied to library and main (change as needed). # Set the properties you require, e.g. what C++ standard to use. Here applied to library and main (change as needed).
set_target_properties( set_target_properties(
${LIBRARY_NAME} main ${LIBRARY_NAME} boltzmann
PROPERTIES PROPERTIES
CXX_STANDARD 17 CXX_STANDARD 17
CXX_STANDARD_REQUIRED YES CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO CXX_EXTENSIONS NO
) )

View File

@@ -63,6 +63,7 @@ Example:
``` bash ``` bash
> mkdir build && cd build > mkdir build && cd build
> conan install ..
> cmake .. -DCMAKE_BUILD_TYPE=[Debug | Coverage | Release] > cmake .. -DCMAKE_BUILD_TYPE=[Debug | Coverage | Release]
> make > make
> ./main > ./main

View File

@@ -1,35 +0,0 @@
// Executables must have the following defined if the library contains
// doctest definitions. For builds with this disabled, e.g. code shipped to
// users, this can be left out.
#ifdef ENABLE_DOCTEST_IN_LIBRARY
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest.h"
#endif
#include <iostream>
#include <stdlib.h>
#include "exampleConfig.h"
#include "example.h"
/*
* Simple main program that demontrates how access
* CMake definitions (here the version number) from source code.
*/
int main() {
std::cout << "C++ Boiler Plate v"
<< PROJECT_VERSION_MAJOR
<< "."
<< PROJECT_VERSION_MINOR
<< "."
<< PROJECT_VERSION_PATCH
<< "."
<< PROJECT_VERSION_TWEAK
<< std::endl;
std::system("cat ../LICENSE");
// Bring in the dummy class from the example source,
// just to show that it is accessible from main.cpp.
Dummy d = Dummy();
return d.doSomething() ? 0 : -1;
}

View File

@@ -5,8 +5,8 @@
# correct definitions. Here only used to make version number available to # correct definitions. Here only used to make version number available to
# the source code. Include "exampleConfig.h" (no .in suffix) in the source. # the source code. Include "exampleConfig.h" (no .in suffix) in the source.
configure_file ( configure_file (
"${PROJECT_SOURCE_DIR}/include/exampleConfig.h.in" "${PROJECT_SOURCE_DIR}/include/kami/config.hpp.in"
"${PROJECT_BINARY_DIR}/exampleConfig.h" "${PROJECT_BINARY_DIR}/include/kami/config.hpp"
) )
# add the binary tree to the search path for include files # add the binary tree to the search path for include files
# so that we will find exampleConfig.h # so that we will find exampleConfig.h

6
conanfile.txt Normal file
View File

@@ -0,0 +1,6 @@
[requires]
catch2/2.2.2@bincrafters/stable
spdlog/1.7.0
[generators]
cmake

151
examples/boltzmann.cpp Normal file
View File

@@ -0,0 +1,151 @@
/*-
* TODO FILEHEADER
*/
#include "boltzmann.hpp"
// #include <spdlog/spdlog.h>
#include <iostream>
#include <kami/agent.hpp>
#include <kami/kami.hpp>
#include <kami/multigrid2d.hpp>
#include <map>
MoneyAgent::MoneyAgent() {
rd = new std::random_device();
rng = new std::mt19937{(*rd)()};
stepCounter = 0;
agentWealth = 1;
}
MoneyAgent::~MoneyAgent() {
delete rng;
delete rd;
};
void MoneyAgent::step() {
stepCounter++;
moveAgent();
if (agentWealth > 0)
giveMoney();
}
void MoneyAgent::setWorld(kami::MultiGrid2D *w) {
world = w;
}
void MoneyAgent::setModel(class BoltzmannWealthModel *m) {
model = m;
}
void MoneyAgent::moveAgent() {
auto agentID = this->getAgentID();
auto moveList = world->getNeighborhood(agentID, kami::NeighborhoodType::Moore, false);
std::uniform_int_distribution<unsigned long> dist(0, moveList.size() - 1);
auto newLocation = moveList[dist(*rng)];
world->moveAgent(agentID, newLocation);
}
int MoneyAgent::getWealth() {
return agentWealth;
}
void MoneyAgent::setWealth(int newWealth) {
agentWealth = newWealth;
}
void MoneyAgent::giveMoney() {
kami::AgentID agentID = getAgentID();
kami::MultiGrid2DCoord location = world->getLocationByAgent(agentID);
std::vector<kami::AgentID> *cellMates = world->getCellContents(location);
if (cellMates->size() > 1) {
std::uniform_int_distribution<unsigned long> dist(0, cellMates->size() - 1);
kami::AgentID otherAgentID = cellMates->at(dist(*rng));
auto otherAgent = model->getAgentByID(otherAgentID);
otherAgent->agentWealth += 1;
agentWealth -= 1;
}
}
void MoneyAgent::prinfo(void) const {
kami::AgentID agentID = getAgentID();
kami::MultiGrid2DCoord location = world->getLocationByAgent(agentID);
std::cout << " agent: " << agentID << " step: " << stepCounter << " wealth: " << agentWealth << " location: " << location << std::endl;
}
BoltzmannWealthModel::BoltzmannWealthModel(unsigned int numberAgents, unsigned int width, unsigned int height) {
auto seed = std::chrono::system_clock::now().time_since_epoch().count();
std::minstd_rand rng(static_cast<unsigned int>(seed));
std::uniform_int_distribution<unsigned long> distWidth(0, width - 1);
std::uniform_int_distribution<unsigned long> distHeight(0, height - 1);
world = new kami::MultiGrid2D(width, height, true, true);
sched = new kami::RandomScheduler(this);
stepCount = 0;
MoneyAgent::setWorld(world);
MoneyAgent::setModel(this);
for (unsigned int i = 0; i < numberAgents; i++) {
MoneyAgent *newAgent = new MoneyAgent();
agentList.insert(std::pair<kami::AgentID, MoneyAgent *>(newAgent->getAgentID(), newAgent));
sched->addAgent(newAgent->getAgentID());
world->addAgent(newAgent->getAgentID(), static_cast<int>(distWidth(rng)), static_cast<int>(distHeight(rng)));
}
}
BoltzmannWealthModel::~BoltzmannWealthModel() {
for (auto agent = agentList.begin(); agent != agentList.end(); ++agent) {
world->deleteAgent(agent->first);
sched->deleteAgent(agent->first);
agentList.erase(agent);
}
delete sched;
delete world;
}
void BoltzmannWealthModel::step() {
stepCount++;
sched->step();
}
void BoltzmannWealthModel::run(unsigned int n) {
for (unsigned int i = 0; i < n; i++)
step();
}
void BoltzmannWealthModel::prinfo(void) const {
std::cout << " step: " << stepCount << std::endl
<< " agentinfo: " << std::endl;
for (auto agent = agentList.begin(); agent != agentList.end(); ++agent) {
agent->second->prinfo();
}
}
MoneyAgent *BoltzmannWealthModel::getAgentByID(kami::AgentID agentID) const {
MoneyAgent *agentPair = agentList.at(agentID);
return agentPair;
}
std::random_device *MoneyAgent::rd = nullptr;
std::mt19937 *MoneyAgent::rng = nullptr;
kami::MultiGrid2D *MoneyAgent::world = nullptr;
BoltzmannWealthModel *MoneyAgent::model = nullptr;
int main(void) {
BoltzmannWealthModel model(100, 10, 10);
for (int i = 0; i < 1000; i++) {
model.step();
}
model.prinfo();
}

60
examples/boltzmann.hpp Normal file
View File

@@ -0,0 +1,60 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef BOLTZMAN_HPP
#define BOLTZMAN_HPP
#include <iostream>
#include <kami/agent.hpp>
#include <kami/kami.hpp>
#include <kami/multigrid2d.hpp>
#include <map>
#include <random>
class MoneyAgent : public kami::Agent {
public:
MoneyAgent();
~MoneyAgent();
void step();
static void setWorld(kami::MultiGrid2D *w);
static void setModel(class BoltzmannWealthModel *m);
void moveAgent();
int getWealth();
void setWealth(int newWealth);
void giveMoney();
void prinfo(void) const;
private:
static kami::MultiGrid2D *world;
static BoltzmannWealthModel *model;
static std::random_device *rd;
static std::mt19937 *rng;
int stepCounter;
int agentWealth;
};
class BoltzmannWealthModel : public kami::Model {
public:
BoltzmannWealthModel(unsigned int = 100, unsigned int = 10, unsigned int = 10);
~BoltzmannWealthModel();
void step();
void run(unsigned int n);
void prinfo(void) const;
MoneyAgent *getAgentByID(kami::AgentID agentID) const;
private:
std::map<kami::AgentID, MoneyAgent *> agentList;
kami::RandomScheduler *sched;
kami::MultiGrid2D *world;
unsigned int stepCount;
};
#endif // BOLTZMAN_HPP

View File

@@ -1,28 +0,0 @@
#pragma once
/**
* This is a dummy class to demonstrate features of the boiler plate.
*/
class Dummy {
public:
/**
* Default constructor for Dummy (does nothing).
*/
Dummy();
/**
* Returns a bool.
* @return Always True.
*/
bool doSomething();
};
#ifdef ENABLE_DOCTEST_IN_LIBRARY
#include "doctest.h"
TEST_CASE("we can have tests in headers if we want")
{
Dummy d;
CHECK(d.doSomething() == true);
}
#endif

59
include/kami/agent.hpp Normal file
View File

@@ -0,0 +1,59 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_AGENT_HPP
#define KAMI_AGENT_HPP
#include <iostream>
#include <string>
namespace kami {
/// A unique identifier for each agent
class AgentID {
public:
/// Create a new unique identifier
AgentID();
std::string toString() const;
friend bool operator==(const AgentID &, const AgentID &);
friend bool operator!=(const AgentID &, const AgentID &);
friend bool operator<(const AgentID &, const AgentID &);
friend std::ostream &operator<<(std::ostream &, const AgentID &);
private:
static uint64_t idGen;
uint64_t id;
};
class Agent {
public:
virtual ~Agent() = default;
AgentID getAgentID() const;
virtual void step();
friend bool operator==(const Agent &, const Agent &);
friend bool operator!=(const Agent &, const Agent &);
private:
AgentID agentID;
};
/// A class for agents with pre-`step()` and post-`step()` staging.
class StagedAgent : public Agent {
public:
///
StagedAgent();
virtual ~StagedAgent() = default;
virtual void preStep() = 0;
virtual void postStep() = 0;
};
} // namespace kami
#endif // KAMI_AGENT_HPP

View File

@@ -6,7 +6,13 @@
* right definition values. Change the namings as you wish, * right definition values. Change the namings as you wish,
* but make sure they match up with whats in CMakeLists.txt. * but make sure they match up with whats in CMakeLists.txt.
*/ */
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@ #pragma once
#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@ #ifndef KAMI_KAMI_VERSION_HPP
#define PROJECT_VERSION_TWEAK @PROJECT_VERSION_TWEAK@ #define KAMI_KAMI_VERSION_HPP
#define KAMI_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define KAMI_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define KAMI_VERSION_PATCH @PROJECT_VERSION_PATCH@
#endif // KAMI_KAMI_VERSION_HPP

27
include/kami/domain.hpp Normal file
View File

@@ -0,0 +1,27 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_DOMAIN_HPP
#define KAMI_DOMAIN_HPP
#include <kami/kami.hpp>
namespace kami {
/**
A domain provides an environment for the agents to participate in
*/
class Domain {
};
/**
A domain based on a grid with integer steps
*/
class GridDomain : public Domain {
};
} // namespace kami
#endif // KAMI_DOMAIN_HPP

13
include/kami/kami.hpp Normal file
View File

@@ -0,0 +1,13 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_KAMI_HPP
#define KAMI_KAMI_HPP
#include <kami/agent.hpp>
#include <kami/model.hpp>
#include <kami/random.hpp>
#endif // KAMI_KAMI_HPP

33
include/kami/model.hpp Normal file
View File

@@ -0,0 +1,33 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_MODEL_HPP
#define KAMI_MODEL_HPP
#include <kami/agent.hpp>
namespace kami {
/// An abstract for generic models
class Model {
public:
virtual ~Model();
/// Get a reference to an Agent by AgentID
virtual Agent *getAgentByID(AgentID) const = 0;
/// Run the model for a fixed number of steps.
void run(unsigned int) { return; }
/// Execute a 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.
void step() { return; }
};
} // namespace kami
#endif // KAMI_MODEL_HPP

View File

@@ -0,0 +1,88 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_MULTIGRID2D_HPP
#define KAMI_MULTIGRID2D_HPP
#include <kami/agent.hpp>
#include <kami/domain.hpp>
#include <kami/kami.hpp>
#include <kami/multigrid2d.hpp>
#include <map>
#include <mutex>
#include <vector>
namespace kami {
typedef enum NeighborhoodType { Moore,
VonNeumann } NeighborhoodType;
class MultiGrid2DCoord {
public:
MultiGrid2DCoord(int, int);
void setCoord(int, int);
void setXCoord(int);
void setYCoord(int);
int getXCoord(void) const;
int getYCoord(void) const;
friend bool operator==(const MultiGrid2DCoord &, const MultiGrid2DCoord &);
friend bool operator!=(const MultiGrid2DCoord &, const MultiGrid2DCoord &);
friend std::ostream &operator<<(std::ostream &, const MultiGrid2DCoord &);
private:
int xCoord;
int yCoord;
};
class MultiGrid2D : public GridDomain {
public:
MultiGrid2D(unsigned int, unsigned int, bool, bool);
~MultiGrid2D(void);
bool addAgent(AgentID, int, int);
bool addAgent(AgentID, MultiGrid2DCoord);
void deleteAgent(AgentID);
void deleteAgent(AgentID, int, int);
void deleteAgent(AgentID, MultiGrid2DCoord);
bool isLocationValid(MultiGrid2DCoord) const;
MultiGrid2DCoord getLocationByAgent(AgentID) const;
void moveAgent(AgentID, MultiGrid2DCoord);
void setColWrap(bool);
void setRowWrap(bool);
bool getColWrap(void) const;
bool getRowWrap(void) const;
std::vector<MultiGrid2DCoord> getNeighborhood(MultiGrid2DCoord, NeighborhoodType, bool) const;
std::vector<MultiGrid2DCoord> getNeighborhood(AgentID, NeighborhoodType, bool) const;
std::vector<AgentID> *getCellContents(MultiGrid2DCoord);
void setMaxRows(unsigned int);
void setMaxCols(unsigned int);
unsigned int getMaxRows(void) const;
unsigned int getMaxCols(void) const;
private:
std::vector<AgentID> **agentGrid;
std::map<AgentID, MultiGrid2DCoord> *agentIndex;
static std::mutex lock;
unsigned int maxRows, maxCols;
bool colWrap, rowWrap;
MultiGrid2DCoord locationWrap(int, int) const;
MultiGrid2DCoord locationWrap(MultiGrid2DCoord) const;
};
} // namespace kami
#endif // KAMI_MULTIGRID2D_HPP

33
include/kami/random.hpp Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#ifndef KAMI_RANDOM_HPP
#define KAMI_RANDOM_HPP
#include <algorithm>
#include <kami/agent.hpp>
#include <kami/model.hpp>
#include <kami/scheduler.hpp>
#include <random>
#include <vector>
namespace kami {
class RandomScheduler : public Scheduler {
public:
RandomScheduler(Model *);
virtual ~RandomScheduler();
void addAgent(AgentID);
void deleteAgent(AgentID);
void step();
private:
std::vector<AgentID> agentList;
std::random_device rd;
std::mt19937 rng{rd()};
Model *model;
int stepCounter;
};
}; // namespace kami
#endif // KAMI_RANDOM_HPP

View File

@@ -0,0 +1,37 @@
/*-
* TODO FILEHEADER
*/
#pragma once
#ifndef KAMI_SCHEDULER_HPP
#define KAMI_SCHEDULER_HPP
#include <kami/agent.hpp>
namespace kami {
/// An abstract class for a Scheduler
class Scheduler {
public:
virtual ~Scheduler();
/// Add an Agent to the Scheduler.
///
/// @param agentID The AgentID of the agent to add.
virtual void addAgent(AgentID agentID) = 0;
/// Remove an Agent from the Scheduler.
///
/// @param agentID The AgentID of the agent to remove.
virtual void deleteAgent(AgentID agentID) = 0;
/// Step the Scheduler.
///
/// A generic step function that executes a single time step.
virtual void step() = 0;
};
} // namespace kami
#endif // KAMI_SCHEDULER_HPP

View File

@@ -1,22 +0,0 @@
#!/bin/bash
# Revert to first commit, add and commit everything as single commit.
git reset $(git commit-tree HEAD^{tree} -m "Bolier plate for C++ project added")
name=$(git config user.name)
email=$(git config user.email)
# If this script is called with an argument, use that as the amended author
# EX: ./setup.sh "Author Name <author_email@email.com>"
if [[ "$1" ]]; then
git commit --amend --author="$1"
else
git commit --amend --author="$name <$email>"
fi
# Initialize submodules: This should already be done when cloning, but there are ways to muck it
# up if you do things in the wrong order. So just to be sure, we do it now.
git submodule update --init --recursive
# Remove the remote (you probably want your own instead).
git remote remove origin

52
src/agent.cpp Normal file
View File

@@ -0,0 +1,52 @@
/*
*
*/
#include "kami/agent.hpp"
#include <string>
namespace kami {
uint64_t AgentID::idGen = 1;
AgentID::AgentID() {
id = idGen++;
}
std::string AgentID::toString() const {
return std::to_string(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.id < rhs.id;
}
std::ostream &operator<<(std::ostream &lhs, const AgentID &rhs) {
return lhs << rhs.id;
}
AgentID Agent::getAgentID() const {
return agentID;
}
void Agent::step() {
}
bool operator==(const Agent &lhs, const Agent &rhs) {
return lhs.agentID == rhs.agentID;
}
bool operator!=(const Agent &lhs, const Agent &rhs) {
return !(lhs == rhs);
}
} // namespace kami

View File

@@ -1,21 +0,0 @@
#include "example.h"
Dummy::Dummy() {
}
bool Dummy::doSomething() {
// Do silly things, using some C++17 features to enforce C++17 builds only.
constexpr int digits[2] = {0, 1};
auto [zero, one] = digits;
return zero + one;
}
#ifdef ENABLE_DOCTEST_IN_LIBRARY
#include "doctest.h"
TEST_CASE("we can have tests written here, to test impl. details")
{
CHECK(true);
}
#endif

10
src/kami.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include "kami/model.hpp"
#include "kami/scheduler.hpp"
namespace kami {
Model::~Model() {}
Scheduler::~Scheduler() {}
} // namespace kami

189
src/multigrid2d.cpp Normal file
View File

@@ -0,0 +1,189 @@
/*-
* TODO FILEHEADER
*/
#include "kami/multigrid2d.hpp"
#include <map>
#include <mutex>
#include <vector>
#include "kami/agent.hpp"
#include "kami/domain.hpp"
#include "kami/kami.hpp"
namespace kami {
MultiGrid2DCoord::MultiGrid2DCoord(int newXCoord, int newYCoord) {
setXCoord(newXCoord);
setYCoord(newYCoord);
}
void MultiGrid2DCoord::setCoord(int newXCoord, int newYCoord) {
setXCoord(newXCoord);
setYCoord(newYCoord);
}
void MultiGrid2DCoord::setXCoord(int newXCoord) {
xCoord = newXCoord;
}
void MultiGrid2DCoord::setYCoord(int newYCoord) {
yCoord = newYCoord;
}
int MultiGrid2DCoord::getXCoord(void) const {
return xCoord;
}
int MultiGrid2DCoord::getYCoord(void) const {
return yCoord;
}
bool operator==(const MultiGrid2DCoord &lhs, const MultiGrid2DCoord &rhs) {
return (lhs.xCoord == rhs.yCoord && lhs.yCoord == rhs.yCoord);
}
bool operator!=(const MultiGrid2DCoord &lhs, const MultiGrid2DCoord &rhs) {
return !(lhs == rhs);
}
std::ostream &operator<<(std::ostream &lhs, const MultiGrid2DCoord &rhs) {
return lhs << "(" << rhs.xCoord << ", " << rhs.yCoord << ")";
}
MultiGrid2D::MultiGrid2D(unsigned int newMaxCols, unsigned int newMaxRows, bool newColWrap = false, bool newRowWrap = false) {
setMaxCols(newMaxCols);
setMaxRows(newMaxRows);
setColWrap(newColWrap);
setRowWrap(newRowWrap);
agentGrid = new std::vector<AgentID> *[newMaxCols];
for (unsigned int i = 0; i < newMaxRows; i++)
agentGrid[i] = new std::vector<AgentID>[newMaxRows];
agentIndex = new std::map<AgentID, MultiGrid2DCoord>;
}
MultiGrid2D::~MultiGrid2D(void) {
delete agentIndex;
for (unsigned int i = 0; i < maxRows; i++)
delete [] agentGrid[i];
delete [] agentGrid;
}
bool MultiGrid2D::addAgent(AgentID agentID, int xCoord, int yCoord) {
return addAgent(agentID, MultiGrid2DCoord(xCoord, yCoord));
}
bool MultiGrid2D::addAgent(AgentID agentID, MultiGrid2DCoord location) {
if (isLocationValid(location)) {
agentIndex->insert(std::pair<AgentID, MultiGrid2DCoord>(agentID, location));
agentGrid[location.getXCoord()][location.getYCoord()].push_back(agentID);
return (true);
}
return (false);
}
void MultiGrid2D::deleteAgent(AgentID agentID) {
MultiGrid2DCoord location = getLocationByAgent(agentID);
deleteAgent(agentID, location);
}
void MultiGrid2D::deleteAgent(AgentID agentID, int xCoord, int yCoord) {
deleteAgent(agentID, MultiGrid2DCoord(xCoord, yCoord));
}
void MultiGrid2D::deleteAgent(AgentID agentID, MultiGrid2DCoord location) {
auto agentList = agentGrid[static_cast<int>(location.getXCoord())][static_cast<int>(location.getYCoord())];
for (auto testAgentID = agentList.begin(); testAgentID < agentList.end(); testAgentID++) {
if (*testAgentID == agentID) {
agentList.erase(testAgentID);
agentIndex->erase(agentID);
}
}
}
bool MultiGrid2D::isLocationValid(MultiGrid2DCoord location) const {
auto xCoord = location.getXCoord();
auto yCoord = location.getYCoord();
return (xCoord >= 0 && xCoord < static_cast<int>(maxCols) && yCoord >= 0 && yCoord < static_cast<int>(maxRows));
}
MultiGrid2DCoord MultiGrid2D::getLocationByAgent(AgentID agentID) const {
return agentIndex->at(agentID);
}
void MultiGrid2D::moveAgent(AgentID agentID, MultiGrid2DCoord nextLocation) {
MultiGrid2DCoord currLocation = getLocationByAgent(agentID);
deleteAgent(agentID, currLocation);
addAgent(agentID, nextLocation);
}
void MultiGrid2D::setColWrap(bool newColWrap) { colWrap = newColWrap; }
void MultiGrid2D::setRowWrap(bool newRowWrap) { rowWrap = newRowWrap; }
bool MultiGrid2D::getColWrap(void) const { return colWrap; }
bool MultiGrid2D::getRowWrap(void) const { return rowWrap; }
std::vector<MultiGrid2DCoord> MultiGrid2D::getNeighborhood(AgentID agentID, NeighborhoodType nType, bool includeCenter) const {
MultiGrid2DCoord location = getLocationByAgent(agentID);
return getNeighborhood(location, nType, includeCenter);
}
std::vector<MultiGrid2DCoord> MultiGrid2D::getNeighborhood(MultiGrid2DCoord location, NeighborhoodType nType, bool includeCenter) const {
std::vector<MultiGrid2DCoord> neighborhood;
auto xCoord = location.getXCoord();
auto yCoord = location.getYCoord();
if (includeCenter == true)
neighborhood.push_back(location);
// N, E, S, W
neighborhood.push_back(locationWrap(xCoord, yCoord - 1));
neighborhood.push_back(locationWrap(xCoord + 1, yCoord));
neighborhood.push_back(locationWrap(xCoord, yCoord + 1));
neighborhood.push_back(locationWrap(xCoord - 1, yCoord));
if (nType == NeighborhoodType::Moore) {
// NE, SE, SW, NW
neighborhood.push_back(locationWrap(xCoord + 1, yCoord - 1));
neighborhood.push_back(locationWrap(xCoord + 1, yCoord + 1));
neighborhood.push_back(locationWrap(xCoord - 1, yCoord + 1));
neighborhood.push_back(locationWrap(xCoord - 1, yCoord - 1));
}
return neighborhood;
}
std::vector<AgentID> *MultiGrid2D::getCellContents(MultiGrid2DCoord location) {
if (isLocationValid(location)) {
return &agentGrid[location.getXCoord()][location.getYCoord()];
}
return nullptr;
}
void MultiGrid2D::setMaxCols(unsigned int newMaxCols) { maxCols = newMaxCols; }
void MultiGrid2D::setMaxRows(unsigned int newMaxRows) { maxRows = newMaxRows; }
unsigned int MultiGrid2D::getMaxCols(void) const { return maxCols; }
unsigned int MultiGrid2D::getMaxRows(void) const { return maxRows; }
MultiGrid2DCoord MultiGrid2D::locationWrap(MultiGrid2DCoord location) const {
return locationWrap(location.getXCoord(), location.getYCoord());
}
MultiGrid2DCoord MultiGrid2D::locationWrap(int xCoord, int yCoord) const {
if (colWrap == true)
xCoord = (xCoord + static_cast<int>(maxCols)) % static_cast<int>(maxCols);
if (rowWrap == true)
yCoord = (yCoord + static_cast<int>(maxRows)) % static_cast<int>(maxRows);
return MultiGrid2DCoord(xCoord, yCoord);
}
} // namespace kami

49
src/random.cpp Normal file
View File

@@ -0,0 +1,49 @@
/*
*
*/
#include "kami/random.hpp"
#include <string>
#include <random>
#include "kami/agent.hpp"
#include "kami/model.hpp"
#include "kami/scheduler.hpp"
namespace kami {
RandomScheduler::RandomScheduler(Model *newModel) {
stepCounter = 0;
model = newModel;
}
RandomScheduler::~RandomScheduler() {}
void RandomScheduler::addAgent(AgentID newAgentID) {
agentList.push_back(newAgentID);
}
void RandomScheduler::deleteAgent(AgentID oldAgentID) {
for (auto agentID = agentList.begin(); agentID < agentList.end(); agentID++) {
if (*agentID == oldAgentID) {
agentList.erase(agentID);
return;
}
}
// ERROR HERE
}
void RandomScheduler::step() {
stepCounter++;
shuffle(agentList.begin(), agentList.end(), rng);
for (auto agentID = agentList.begin(); agentID < agentList.end(); agentID++) {
Agent *agent = model->getAgentByID(*agentID);
if (agent != nullptr)
agent->step();
// ERROR HERE
}
}
} // namespace kami

View File

@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.8.2)
# List all files containing tests. (Change as needed) # List all files containing tests. (Change as needed)
set(TESTFILES # All .cpp files in tests/ set(TESTFILES # All .cpp files in tests/
main.cpp
dummy.cpp dummy.cpp
) )

View File

@@ -1,11 +1,5 @@
#include "doctest.h" #include <iostream>
#include "example.h"
// Tests that don't naturally fit in the headers/.cpp files directly int main(void) {
// can be placed in a tests/*.cpp file. Integration tests are a good example. std::cout << "foo";
TEST_CASE("complicated integration tests could be here")
{
Dummy d;
CHECK(d.doSomething() == true);
} }

View File

@@ -1,5 +0,0 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"
// This is all that is needed to compile a test-runner executable.
// More tests can be added here, or in a new tests/*.cpp file.