Skip to content

model implementation #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
987e24c
Add state node attribute to metadate file!
Aug 13, 2018
aad9b73
Set up variables
Aug 13, 2018
99dcdc6
Add logic to skip edge cases
Aug 13, 2018
645d2f3
Add logic to handle toroidal edge cases
Aug 13, 2018
1fce878
Refactor and tidy code
Aug 13, 2018
136c815
Add logic to load next state of cells
Aug 13, 2018
fa9a0ba
Add toroidal option and egde case value
Aug 13, 2018
101d3ef
Add variables for options
Aug 13, 2018
93681e3
Add logic for setting value of edge cases
Aug 13, 2018
bbfe022
Bug fix
Aug 13, 2018
62f903f
Add descriptive comments
Aug 13, 2018
2be6e70
Update metadate file
Aug 13, 2018
9a329e9
Edit metadata file
Aug 15, 2018
430db1b
Edit metadata file
Aug 15, 2018
461752a
Wrap next state logic in switch case based on selected rule
Aug 15, 2018
9533ea8
Add logic for rule 110
Aug 15, 2018
661a1ea
Add logic for rules 32 and 250
Aug 15, 2018
27ddd2b
Add supported graph to metadata file
Aug 15, 2018
fc583a7
fix algorithm implementation + add README and examples
cardinot Aug 22, 2018
f7748e4
README - minor fixes
cardinot Aug 22, 2018
3752a91
update cmake + minor fix
cardinot Sep 1, 2018
9b43151
update citation
cardinot Oct 4, 2018
1c718ca
update readme.md
cardinot Apr 16, 2019
3439bfa
Parse all the 256 Elementary Cellular Automata rules
Sedictious Apr 26, 2019
39fff3e
Minor fixes
Sedictious Apr 28, 2019
fcf958e
Update readme
Sedictious Apr 28, 2019
dc8a743
Add missing header
Sedictious Apr 28, 2019
9eb99ca
Update metadata
Sedictious Apr 28, 2019
f3b31fc
Update README.md
cardinot Apr 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 6 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ get_filename_component(PLUGIN_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
set(PLUGIN_NAME plugin_${PLUGIN_NAME})
project(${PLUGIN_NAME})

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

find_package(EvoplexCore 0.1.0 REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(EvoplexCore 0.2.0 REQUIRED)
find_package(Qt5Core 5.8.0 REQUIRED)
find_package(Qt5Concurrent 5.8.0 REQUIRED)
find_package(Qt5Network 5.8.0 REQUIRED)

# set compilation and installation directories
if(APPLE)
Expand All @@ -30,23 +31,8 @@ else()
endif()
set(PLUGIN_OUTPUT_LIBRARY "${CMAKE_BINARY_DIR}/plugin")

# https://cmake.org/Wiki/CMake_RPATH_handling
# use, i.e. don't skip the full RPATH for the build tree
set(CMAKE_SKIP_BUILD_RPATH FALSE)
# when building, don't use the install RPATH already (but later on when installing)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib/evoplex")
# add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# the RPATH to be used when installing, but only if it's not a system directory
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib/evoplex" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib/evoplex")
endif("${isSystemDir}" STREQUAL "-1")

add_library(${PLUGIN_NAME} SHARED plugin.cpp)
target_link_libraries(${PLUGIN_NAME} PRIVATE Evoplex::EvoplexCore Qt5::Core)
target_link_libraries(${PLUGIN_NAME} PUBLIC Evoplex::EvoplexCore)
set_target_properties(${PLUGIN_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${PLUGIN_OUTPUT_LIBRARY}
ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PLUGIN_OUTPUT_LIBRARY}
Expand Down
110 changes: 66 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,77 @@
# Evoplex: Minimal Model

This is a minimum example of a model plugin for [Evoplex](https://evoplex.github.io). It has the essential files for you to create a new model plugin:
``` bash
├── CMakeLists.txt
├── metadata.json
├── plugin.cpp
└── plugin.h
```
You do not need to touch the `CMakeLists.txt` file. Also, you must NOT rename any of those files.
# Cellular Automata 1D Model

:point_right: **Note:** you *DO NOT* need to compile Evoplex from source to be able to create plugins.
## What is it?

### Installing dependencies
* If you compiled Evoplex from source, you already have all dependencies to compile a plugin and *DO NOT* have to install anything else.
* If you installed Evoplex from the binary packages, you will have to install the dependencies as follows:
* [Instructions for Linux](https://github.com/evoplex/evoplex/wiki/Building-on-Linux#installing-dependencies)
* [Instructions for MacOS](https://github.com/evoplex/evoplex/wiki/Building-on-MacOS#installing-dependencies)
* [Instructions for Windows](https://github.com/evoplex/evoplex/wiki/Building-on-Windows#installing-dependencies)
This is a model plugin for [Evoplex](https://evoplex.org) and is included by default in the software.

### Compiling this plugin
It implements the [256 elementary cellular automaton rules](http://mathworld.wolfram.com/ElementaryCellularAutomaton.html).

:point_right: if you compiled Evoplex from source in Debug mode, you should also compile your plugin in Debug mode.
## How it works

:point_right: the plugin must be compiled with the same architecture (32/64 bits) of Evoplex.
The model runs in a lattice grid, i.e., it uses the `squareGrid` graph generator.

#### from QtCreator
* Open the `CMakeLists.txt`
* In the projects page, make sure the `EvoplexCore_DIR` is set. If it shows `EvoplexCore_DIR-NOTFOUND` and you compiled Evoplex from source (eg., at `~/evoplex/build`), set it to `~/evoplex/build/src/core/EvoplexCore/` as shown [here](https://i.imgur.com/hyKuFR3.png).
* Build
Each cell (node in the graph) can be in one of two possible states: on or off.

#### from command line
Assuming you placed this repository at `~/evoplex/minimal-model` and you are at `~/evoplex`, just run the commands below:
``` bash
mkdir build-plugin
cd build-plugin
cmake ../minimal-model
cmake --build .
```
When you run the `cmake` command, you might get an **error** like `FindEvoplexCore.cmake` not found. If you compiled Evoplex from source (eg., at `~/evoplex/build`), just run the command below:
``` bash
export EvoplexCore_DIR=~/evoplex/build/src/core/EvoplexCore/
```
Starting from the first row in the graph, at each time step:

- based on the selected rule, compute the next state for each cell in the current row;
- assign the new states to the row below.

## Parameters

``rule`` :
An integer between 0 and 255. Its 8-bit binary representation will indicate the transition rule.

For example, for rule 110:

(110)<sub>10</sub> = (01101110)<sub>2</sub>

| pattern |111|110|101|100|011|010|001|000|
|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|**state**| 0 | 1 | 1 | 0 | 1 | 1 | 1 | 0 |

## Examples

## Running this plugin
After compiling the plugin, open Evoplex, go to the `Plugins` page, click on `import` and select the `plugin_minimal-model` file at `~/evoplex/minimal-model/build/plugin/`. The plugin will now be available in the `Projects` page.
The figures below were produced using this model in Evoplex.

## Support
- Ask a question in the [mailing list](https://groups.google.com/group/evoplex) (or send it directly to [email protected])
- Follow us on [Twitter](https://twitter.com/EvoplexMAS)
- Join us on our [Gitter chat channel](https://gitter.im/EvoplexMAS/evoplex)
<p align="center">
<img src="example1.gif" alt="Example" width="70%"></br>
Rule 30: initial population with all cells off (blue) and one on-cell in the first row.
</p>

<p align="center">
<img src="example2.gif" alt="Example" width="70%"></br>
Rule 110: random initial population.
</p>

<p align="center">
<img src="example3.gif" alt="Example" width="70%"></br>
Rule 110: initial population with all cells off (blue) and one on-cell in the first row.
</p>

## References
- [1] Weisstein, Eric W. "Elementary Cellular Automaton." From MathWorld--A Wolfram Web Resource. [http://mathworld.wolfram.com/ElementaryCellularAutomaton.html](http://mathworld.wolfram.com/ElementaryCellularAutomaton.html)
- [2] Weisstein, Eric W. "Rule 30." From MathWorld--A Wolfram Web Resource. [http://mathworld.wolfram.com/Rule30.html](http://mathworld.wolfram.com/Rule30.html)
- [3] Weisstein, Eric W. "Rule 110." From MathWorld--A Wolfram Web Resource. [http://mathworld.wolfram.com/Rule110.html](http://mathworld.wolfram.com/Rule110.html)

## How to cite
If you mention this model or the Evoplex software in a publication, please cite it as:

> Cardinot, M., O’Riordan, C., Griffith, J., & Perc, M. (2019). Evoplex: A platform for agent-based modeling on networks. SoftwareX, 9, 199-204. https://doi.org/10.1016/j.softx.2019.02.009

```
@article{Evoplex,
author = "Marcos Cardinot and Colm O’Riordan and Josephine Griffith and Matjaž Perc",
title = "Evoplex: A platform for agent-based modeling on networks",
journal = "SoftwareX",
volume = "9",
pages = "199 - 204",
year = "2019",
issn = "2352-7110",
doi = "10.1016/j.softx.2019.02.009",
url = "http://www.sciencedirect.com/science/article/pii/S2352711018302437"
}
```

## Licensing
This plugin is available freely under the [MIT license](https://opensource.org/licenses/MIT).
## License
This plugin is licensed under the [MIT License](https://opensource.org/licenses/MIT) terms.
Binary file added example1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example3.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 7 additions & 9 deletions metadata.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
{
"type": "model",
"uid": "minimalModel",
"uid": "cellularAutomata1D",
"version": 1,
"title": "Mininal Model",
"author": "Evoplex",
"description": "This is a mininal example of a model plugin for Evoplex.",
"title": "Cellular Automata 1D",
"author": "Ethan Padden, Marcos Cardinot and Eleftheria Chatziargyriou",
"description": "This model implements elementary cellular automata.",

"pluginAttributesScope": [],
"nodeAttributesScope": [],
"edgeAttributesScope": [],
"pluginAttributesScope": [ {"rule": "int[0,255]"} ],
"nodeAttributesScope": [ {"state": "bool"} ],

"supportedGraphs": [],
"customOutputs": []
"supportedGraphs": [ "squareGrid" ]
}
83 changes: 77 additions & 6 deletions plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,22 +1,93 @@
/**
* Evoplex <https://evoplex.org>
* Copyright (C) 2016-present
* Copyright (c) 2018 - Marcos Cardinot <[email protected]>
* Copyright (c) 2018 - Ethan Padden <[email protected]>
*
* This source code is licensed under the MIT license found in
* the LICENSE file in the root directory of this source tree.
*/

#include "plugin.h"

namespace evoplex {

bool MinimalModel::init()
bool CellularAutomata1D::init()
{
// this model is only valid for `squareGrid` graph
if (graphId() != "squareGrid" || !graph()->attrExists("boundary") ||
!graph()->attrExists("width") || !graph()->attrExists("height")) {
return false;
}

// starts reading from row=0
m_currRow = 0;

// checks if the `squareGrid` was set with periodic bondary conditions (i.e., a toroid)
m_toroidal = graph()->attr("boundary") == "periodic";
// gets the `squareGrid` width
m_width = graph()->attr("width").toInt();
// gets the `squareGrid` height
m_height = graph()->attr("height").toInt();

if (m_height < 2) {
qWarning() << "the 'squareGrid' height must be >= 2";
return false;
}

// gets the id of the `state` node's attribute, which is the same for all nodes
m_stateAttrId = node(0).attrs().indexOf("state");

// determines which rule to use
m_binrule = std::bitset<8>(attr("rule").toInt());

return m_stateAttrId >= 0;
}

bool CellularAutomata1D::algorithmStep()
{
// 1. gets first node in the current row
Node first = node(linearIdx(m_currRow, 0));

// 2. for each node (starting from the second),
int lastColumn = m_width - 1;
for (int col = 1; col < lastColumn; ++col) {
Node central = node(first.id() + col);
// a. compute the next state based on its neighbours on the left and right
Value state = nextState(node(central.id()-1), central, node(central.id()+1));
// b. assign the next state to the node below the current node
node(central.id()+m_width).setAttr(m_stateAttrId, state);
}

// 3. edge case: if the graph is a toroid, we compute the state for the last column
if (m_toroidal) {
Node last = node(linearIdx(m_currRow, lastColumn));
// a. compute the next state based on its left neighbour and the first node in the row
Value state = nextState(node(last.id()-1), last, first);
// b. assign the next state to the first node of the next row
node(first.id()+m_width).setAttr(m_stateAttrId, state);
}

++m_currRow;
if (m_currRow == m_height-1) {
// all rows have been filled; return false to stop the simulation
return false;
}
return true;
}

bool MinimalModel::algorithmStep()
Value CellularAutomata1D::nextState(const Node& leftNode, const Node& node, const Node& rightNode) const
{
bool left = leftNode.attr(m_stateAttrId).toBool();
bool center = node.attr(m_stateAttrId).toBool();
bool right = rightNode.attr(m_stateAttrId).toBool();

return Value(m_binrule[left*4 + center*2 + right]);
}

int CellularAutomata1D::linearIdx(int row, int col) const
{
return false;
return row * m_width + col;
}

} // evoplex
REGISTER_PLUGIN(MinimalModel)
REGISTER_PLUGIN(CellularAutomata1D)
#include "plugin.moc"
54 changes: 25 additions & 29 deletions plugin.h
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
/**
* Evoplex <https://evoplex.org>
* Copyright (C) 2016-present
* Copyright (c) 2018 - Marcos Cardinot <[email protected]>
* Copyright (c) 2018 - Ethan Padden <[email protected]>
*
* This source code is licensed under the MIT license found in
* the LICENSE file in the root directory of this source tree.
*/

#ifndef MINIMAL_MODEL_H
#define MINIMAL_MODEL_H
#ifndef CELLULARAUTOMATA1D_H
#define CELLULARAUTOMATA1D_H

#include <bitset>
#include <plugininterface.h>

namespace evoplex {
class MinimalModel: public AbstractModel
class CellularAutomata1D: public AbstractModel
{
public:
// Initializes the model.
// This method is called when the model is created and
// is mainly used to validate inputs and set the environment.
// Return true if successful
bool init() override;
bool algorithmStep() override;

// [OPTIONAL]
// It is executed before the algorithmStep() loop
// The default implementation of this method does nothing.
// void beforeLoop() override;
private:
int m_currRow;

// It is executed in a loop and must contain all the logic to perform ONE step.
// Return true if algorithm is good for another step or false to stop asap.
bool algorithmStep() override;
int m_stateAttrId; // the id of the `state` node attribute
std::bitset<8> m_binrule; // binary representation of the automaton rule

bool m_toroidal; // true if the graph is a toroid
int m_width; // the number of columns in the `squareGrid` graph
int m_height; // the number of rows in the `squareGrid` graph

// returns the next state of a node based on the state
// of itself and its neighbours on the left and right
Value nextState(const Node& leftNode, const Node& node, const Node& rightNode) const;

// [OPTIONAL]
// It is executed after the algorithmStep() loop ends.
// The default implementation of this method does nothing.
// void afterLoop() override;

// [OPTIONAL]
// It allows implementing custom outputs which can be plotted or stored
// in a file through Evoplex. The "inputs" must be defined in the
// metadata.json file. If an experiment requests some custom output,
// this method will be called once at each time step, receiving the
// requested inputs.
// Values customOutputs(const Values& inputs) const override;
// return the linear index of an element in a matrix.
int linearIdx(int row, int col) const;
};
} // evoplex
#endif // MINIMAL_MODEL_H
#endif // CELLULARAUTOMATA1D_H