diff --git a/CMakeLists.txt b/CMakeLists.txt
index 91b12b7..b8758d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
@@ -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}
diff --git a/README.md b/README.md
index 5aa38e4..fef1499 100644
--- a/README.md
+++ b/README.md
@@ -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)10 = (01101110)2
+
+| 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 evoplex@googlegroups.com)
-- Follow us on [Twitter](https://twitter.com/EvoplexMAS)
-- Join us on our [Gitter chat channel](https://gitter.im/EvoplexMAS/evoplex)
+
+
+Rule 30: initial population with all cells off (blue) and one on-cell in the first row.
+
+
+
+
+Rule 110: random initial population.
+
+
+
+
+Rule 110: initial population with all cells off (blue) and one on-cell in the first row.
+
+
+## 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.
diff --git a/example1.gif b/example1.gif
new file mode 100644
index 0000000..111709b
Binary files /dev/null and b/example1.gif differ
diff --git a/example2.gif b/example2.gif
new file mode 100644
index 0000000..e0b2e36
Binary files /dev/null and b/example2.gif differ
diff --git a/example3.gif b/example3.gif
new file mode 100644
index 0000000..f805da2
Binary files /dev/null and b/example3.gif differ
diff --git a/metadata.json b/metadata.json
index c8ec5ab..b7aec82 100644
--- a/metadata.json
+++ b/metadata.json
@@ -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" ]
}
diff --git a/plugin.cpp b/plugin.cpp
index fa00b0b..5b83627 100644
--- a/plugin.cpp
+++ b/plugin.cpp
@@ -1,22 +1,93 @@
/**
- * Evoplex
- * Copyright (C) 2016-present
+ * Copyright (c) 2018 - Marcos Cardinot
+ * Copyright (c) 2018 - Ethan Padden
+ *
+ * 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"
diff --git a/plugin.h b/plugin.h
index fbed7ed..c4bb493 100644
--- a/plugin.h
+++ b/plugin.h
@@ -1,44 +1,40 @@
/**
- * Evoplex
- * Copyright (C) 2016-present
+ * Copyright (c) 2018 - Marcos Cardinot
+ * Copyright (c) 2018 - Ethan Padden
+ *
+ * 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
#include
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