diff --git a/.gitignore b/.gitignore
index 05588e2..aea023b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,13 @@
# Own stuff
build/
Makefile
-.vscode/
external/lemon/
external/lemon.tar.gz
# Python
__pycache__
+out/
+logs/
# Prerequisites
*.d
@@ -40,3 +41,5 @@ __pycache__
*.exe
*.out
*.app
+
+.vscode/*
diff --git a/.gitmodules b/.gitmodules
index 42d7939..a311246 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
[submodule "external/eigen"]
path = external/eigen
url = https://gitlab.com/libeigen/eigen.git
+[submodule "external/thread-pool"]
+ path = external/thread-pool
+ url = https://github.com/bshoshany/thread-pool
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000..e50cbb8
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,26 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+# Python 3.9 problem: see https://github.com/readthedocs/readthedocs.org/issues/7554#issuecomment-785114155
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3.9"
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+ configuration: python/docs/source/conf.py
+
+# If using Sphinx, optionally build your docs in additional formats such as PDF
+formats:
+ - pdf
+
+# Optionally declare the Python requirements required to build your docs
+# python:
+# install:
+# - requirements: docs/requirements.txt
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..ce7d0a1
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "python.formatting.autopep8Args": [
+ "--max-line-length",
+ "100"
+ ]
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c3e060..7b00236 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,24 +6,31 @@ option(MAJORMINER_BUILD_TESTS "Build majorminer test executable" ON)
enable_language(C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
-set(CMAKE_BUILD_TYPE Debug)
-set(MM_INCLUDE_LIBS external/oneTBB/include external/eigen build/external/lemon/ external/lemon/ src/)
+set(CMAKE_BUILD_TYPE Release)
+set(MM_INCLUDE_LIBS external/oneTBB/include external/eigen build/external/lemon/ external/lemon/ external/ src/)
set(MM_LINK_LIBS TBB::tbb lemon)
# neither build tests nor tbbmalloc in oneTBB
set(TBB_TEST CACHE BOOL OFF)
set(TBBMALLOC_BUILD CACHE BOOL OFF)
+set(TBB_DISABLE_HWLOC_AUTOMATIC_SEARCH CACHE BOOL OFF)
+
+set(LEMON_ENABLE_GLPK CACHE BOOL OFF)
+set(LEMON_ENABLE_ILOG CACHE BOOL OFF)
+set(LEMON_ENABLE_ILOG CACHE BOOL OFF)
+set(LEMON_ENABLE_COIN CACHE BOOL OFF)
+set(LEMON_ENABLE_SOPLEX CACHE BOOL OFF)
+
# build NetworkSimplex, gtest and oneTBB
add_subdirectory(external)
-
if ( CMAKE_COMPILER_IS_GNUCC )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fdiagnostics-color=always")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Werror -fdiagnostics-color=always")
endif()
if ( MSVC )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX")
endif()
add_library(majorminer)
diff --git a/README.md b/README.md
index 662bb76..fc176f8 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,24 @@
-# majorminer
+# graph-embedder
+[](https://majorminer.readthedocs.io/en/latest/?badge=latest)
+
+
Testing a bunch of graph minor embedding heuristics and related techniques to improve the embedding of QUBOs.
+Our final results for the project can be found [here](doc/Studienarbeit.pdf).
+
-| :warning: | This is a research repo, so APIs and algorithms might change frequently as were are trying out different ideas. Moreover, this means that the code is not production-ready. |
+
+| :warning: | This is a research repo, so APIs and algorithms might change frequently as we are trying out different ideas. Moreover, this means that the code is not production-ready. |
|---------------|:------------------------|
| :point_up: | We currently do not implement the same approaches in C++ and Python, but try out different ideas in different programming languages. Make sure to check out both the C++ and Python implementation. |
|---------------|:------------------------|
+# Python
+All Python-related code and documentation can be found [in the Python folder](python/).
-
-
- C++
-
-# Build C++ library
+# C++
+## Build C++ library
Note that in order to build, you have to clone the submodules as well. That is,
if you have already cloned this repository, you should run ```git submodule update --init --recursive``` and find the submodules in ```external/```.
In the case, you are about to clone the repository, just run ```git clone --recursive https://github.com/MinorEmbedding/majorminer.git```.
@@ -27,17 +32,10 @@ cmake .. -DMAJORMINER_BUILD_TESTS=[ON|OFF] # depending on whether you want to ru
make
```
-# Libraries used in the C++-Project
+## Libraries used in the C++-Project
#### [oneTBB](https://github.com/oneapi-src/oneTBB) (License: [Apache 2.0](https://choosealicense.com/licenses/apache-2.0/))
#### [GoogleTest](https://github.com/google/googletest) (License: [BSD 3-Clause "New" or "Revised"](https://choosealicense.com/licenses/bsd-3-clause/))
#### [LEMON](https://lemon.cs.elte.hu/trac/lemon) (License: [Boost Software License 1.0](https://choosealicense.com/licenses/bsl-1.0/))
#### [Eigen](https://eigen.tuxfamily.org/index.php?title=Main_Page) (License: [MPL2](https://choosealicense.com/licenses/mpl-2.0/), disabled LGPL features.)
-
-
+#### [thread-pool](https://github.com/bshoshany/thread-pool) (License: [MIT](https://choosealicense.com/licenses/mit/))
-
-
-Python
-
-All Python-related code and documentation can be found [in the Python folder](python/).
-
diff --git a/doc/Studienarbeit.pdf b/doc/Studienarbeit.pdf
new file mode 100755
index 0000000..0e91377
Binary files /dev/null and b/doc/Studienarbeit.pdf differ
diff --git a/external/thread-pool b/external/thread-pool
new file mode 160000
index 0000000..b6cd773
--- /dev/null
+++ b/external/thread-pool
@@ -0,0 +1 @@
+Subproject commit b6cd773f37b1be7718f771ae7403726a28be5f40
diff --git a/img/chimera_clique_12_95.svg b/img/chimera_clique_12_95.svg
new file mode 100644
index 0000000..6b26fb2
--- /dev/null
+++ b/img/chimera_clique_12_95.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_15_170.svg b/img/chimera_clique_15_170.svg
new file mode 100644
index 0000000..1b68a2b
--- /dev/null
+++ b/img/chimera_clique_15_170.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_18_211.svg b/img/chimera_clique_18_211.svg
new file mode 100644
index 0000000..9da4d72
--- /dev/null
+++ b/img/chimera_clique_18_211.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_21_302.svg b/img/chimera_clique_21_302.svg
new file mode 100644
index 0000000..4bb4bed
--- /dev/null
+++ b/img/chimera_clique_21_302.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_25_421.svg b/img/chimera_clique_25_421.svg
new file mode 100644
index 0000000..65ddd27
--- /dev/null
+++ b/img/chimera_clique_25_421.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_28_543.svg b/img/chimera_clique_28_543.svg
new file mode 100644
index 0000000..86098ec
--- /dev/null
+++ b/img/chimera_clique_28_543.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_31_653.svg b/img/chimera_clique_31_653.svg
new file mode 100644
index 0000000..2dd136f
--- /dev/null
+++ b/img/chimera_clique_31_653.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_33_767.svg b/img/chimera_clique_33_767.svg
new file mode 100644
index 0000000..67c3a66
--- /dev/null
+++ b/img/chimera_clique_33_767.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_34_799.svg b/img/chimera_clique_34_799.svg
new file mode 100644
index 0000000..b657d38
--- /dev/null
+++ b/img/chimera_clique_34_799.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/img/chimera_clique_8_19.svg b/img/chimera_clique_8_52.svg
similarity index 70%
rename from img/chimera_clique_8_19.svg
rename to img/chimera_clique_8_52.svg
index 7fa9772..d91669c 100644
--- a/img/chimera_clique_8_19.svg
+++ b/img/chimera_clique_8_52.svg
@@ -1 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/include/majorminer_lib.hpp b/include/majorminer_lib.hpp
new file mode 100644
index 0000000..883a53b
--- /dev/null
+++ b/include/majorminer_lib.hpp
@@ -0,0 +1,15 @@
+#ifndef __MAJORMINER_MAJORMINER_LIB_HPP_
+#define __MAJORMINER_MAJORMINER_LIB_HPP_
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
\ No newline at end of file
diff --git a/python/Dockerfile b/python/Dockerfile
new file mode 100644
index 0000000..064a675
--- /dev/null
+++ b/python/Dockerfile
@@ -0,0 +1,12 @@
+FROM python:3.9.10
+WORKDIR /app
+
+RUN mkdir /app/out
+RUN mkdir /app/logs
+
+COPY requirements.txt .
+RUN pip install -r requirements.txt
+
+COPY ./src /app/src
+
+ENTRYPOINT [ "python", "-m", "src.solver.evolution" ]
\ No newline at end of file
diff --git a/python/README.md b/python/README.md
index 31e3a40..027fd41 100644
--- a/python/README.md
+++ b/python/README.md
@@ -1,5 +1,8 @@
# Python evolutionary embedding
+| :warning: | This Readme is currently outdated. You can find the [documentation here](https://majorminer.readthedocs.io/)|
+|---------------|:------------------------|
+
## Usage
Execute (from within the python folder):
@@ -16,4 +19,4 @@ In order to get **144 unique K4 embeddings on a single chimera cell**, execute (
python -m src.solver.k4_results
```
-
\ No newline at end of file
+
diff --git a/python/docs/Majorminer Python class diagram.drawio b/python/docs/Majorminer Python class diagram.drawio
new file mode 100644
index 0000000..7e1f2c3
--- /dev/null
+++ b/python/docs/Majorminer Python class diagram.drawio
@@ -0,0 +1 @@
+7Vtdc9o4FP01zOw+pGPZfPURCEmbpiktabNvjLAFVpEtVhYh5Nf3ypYxRkBMFgJLmMlkrGtZsu85ks+RRclpBU/XAo/9r9wjrGRb3lPJuSzZdg1V4b8KzJJAGX1MAkNBvSSEskCXPhMdtHR0Qj0S5SpKzpmk43zQ5WFIXJmLYSH4NF9twFm+1zEeEiPQdTEzow/Uk34Srdu1LP6J0KGf9oyq+vkCnFbWTxL52OPThZDTLjktwblMjoKnFmEqd2leHj7PHtjtqHp98z36F/9sfrm/+3WRNHa1zSXzRxAklK9u+nk0uPr0q/z7n3Hn6vvUum70by70JdYjZhOdr5+hRwUAQbyYDw3v9y2NpM6AnKVpjaY0YDiEUnPAQ9nVZxCUMaPDEI5duFsiIPBIhKSASEOfkHwMUdenzLvFMz5RzxRJ7I7SUtPngj5Ds5jpNuG0kJpcdjVXo6uuhLAFUUEiqNNJE4XmoVscSV3H5YzhcUT78xsOsBjSsMml5EHaEJ+EHvF0aY58XJCCj+ZcUtcXhEfDqLJBnhbIqeG6JjwgUsygij5rOxoePfRQWp5mREZVHfMXSVwt6wGkB89w3va8ux+AMQ6HkISsP3upP7tgf3Y13x1mAHyIJWmqNEaLtISDhUfNQjFZtyAuMoh7hwNi0BQyLRcoychAriVkNMYuDYe3cZ3Lchb5oZ9UhThcO2AxGXzqeSSMySKxxAmfFEPGnIYyTkWlCX+QsJb1oVKqwA21oIyyMvyp6kK2eAi8wjQmEAGyToki7ApqbRzGL1NrlkdsW2QXiZSDdFv8bAO/js9DRca7SdCHaePUkNwwo/gyYPpwX3hX7LfDu35Rrt/41K98Cab3d21+83g5uCif8V6Pt4FjUQqsxbtWP/D4dgy82wGm6rKG58E7OXrXgO9+gCOrfGDEzRFuQMxoLBh1OtBKMfUC/gEgqZpLAb9XfLi8QAYpHJMUzgoCMNwnrMMjKilX7Yuk7hIxDvWaLqz46nsCtWJO2xPh+jhSMzfo7BGkNz46wQG9P1APPTlXDVS7cuKpxyxo86yzzdudzUNLtsupFrV5zoZhv97moSVb6dSP1+bV1jP1VIVjwWmnWphmx2L56gaWDbh7tXxnW1/hVXJySO5UEW6N91tavpV3/PEsCHcOalFfty89mK7qL4D6GSZ+qw1o0D6OXzP3XAVCwVVzJzakF0VQeV8g1w89UyNzdfWaqFdulwQ0xEIhfo9HkOxTw3dfkCJ06Nk4vYFN0zEJvYb65AalPuNKbjchpPU4spLiFWXpq+sFwZx//xFvSNKhQ1ifT9tZoBkH4ETKlK3ldsTBl5KXIQODMSQF7Jy6243ArgJSEIYlfcx/edwgzjuKuJkwt628MLctJ99E8pD6KnvhU9+2DSVZMBra2ccZc/WvI/iARBE39frZYu7fYjrLlq+oxaxZL5J4hcN0ygUcZu04HCYy1y27mGE9477Dd9t88P5/nCUylykN9N671dge1qIGcm9ew1ymfFeKJUXsqCULWprpa6+ULM5SQ3Zt6V72LVnMlUa99akdQssPVPotHknzK8d5I9T+5Uul8tqNSdar9IvRX7lofwfQL+ayak/yXsjjXZcNRVYi//r73aqZWmGyHY2aMRdOe24898RwetQ9RTx3uli+PeoHXy23Tc981rD/GdZDr5fbprvEntdTUg1m6RMcxntD8uCL4rZpMgUJIL1nNLdH803Xw1duSDU/cYC96AmCXV/l8mTBfM1e0wTf49jQtBJM89tGDszeFOxboqHOuG6Ba/UN95SuxNX82twIoTyZ/0YJCvHPlAxQQUCO1WHIpVI7U59K0gWoVGwKV+RlVB+c8zBWoN8mMlFZcdzDYvRNASxVSqwPVkUhnrjvWtHUr/fAhbeEIeujgUR9BRBok99dgwQUs9+wJa40+yGg0/4D
\ No newline at end of file
diff --git a/python/docs/make.bat b/python/docs/make.bat
new file mode 100644
index 0000000..e5baf6b
--- /dev/null
+++ b/python/docs/make.bat
@@ -0,0 +1,37 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
+
+pause
diff --git a/python/src/graphs/__init__.py b/python/docs/source/_static/.gitkeep
similarity index 100%
rename from python/src/graphs/__init__.py
rename to python/docs/source/_static/.gitkeep
diff --git a/python/docs/source/_static/embedding_solver_principle.png b/python/docs/source/_static/embedding_solver_principle.png
new file mode 100644
index 0000000..1435031
Binary files /dev/null and b/python/docs/source/_static/embedding_solver_principle.png differ
diff --git a/python/docs/source/_static/python_architecture.png b/python/docs/source/_static/python_architecture.png
new file mode 100644
index 0000000..99b8eae
Binary files /dev/null and b/python/docs/source/_static/python_architecture.png differ
diff --git a/python/docs/source/_templates/.gitkeep b/python/docs/source/_templates/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/python/docs/source/api.rst b/python/docs/source/api.rst
new file mode 100644
index 0000000..9f96d28
--- /dev/null
+++ b/python/docs/source/api.rst
@@ -0,0 +1,31 @@
+.. _api:
+
+API Reference
+=============
+
+
+Graph Module
+------------
+
+.. automodule:: src.graph.undirected_graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: src.graph.embedding_graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+.. automodule:: src.graph.chimera_graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+More Modules
+------------
+
+.. note::
+
+ To come soon...
\ No newline at end of file
diff --git a/python/docs/source/conf.py b/python/docs/source/conf.py
new file mode 100644
index 0000000..286b36e
--- /dev/null
+++ b/python/docs/source/conf.py
@@ -0,0 +1,82 @@
+# Great tutorial for this setup
+# https://samnicholls.net/2016/06/15/how-to-sphinx-readthedocs/#fn-841-5
+
+# In order to build run the following commands:
+# luckily ReadTheDocs is doing this automatically for us
+
+# https://stackoverflow.com/a/46349694
+# cd docs/
+# sphinx-apidoc -o source/ ../src -f
+# and after that run:
+# ./make.bat html
+
+
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+
+# https://stackoverflow.com/a/44980548
+sys.path.insert(0, os.path.abspath('../..'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'majorminer'
+copyright = '2021, Dominic Plein, Julien Meier'
+author = 'Dominic Plein, Julien Meier'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.autosummary"
+]
+
+# Napoleon setup
+napoleon_google_docstring = True # defaults to True
+napoleon_use_ivar = True
+
+# Inheritance Diagram
+# https://www.sphinx-doc.org/en/master/usage/extensions/inheritance.html
+# inheritance_graph_attrs = dict(
+# rankdir="TB",
+# size='""'
+# )
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
diff --git a/python/docs/source/index.rst b/python/docs/source/index.rst
new file mode 100644
index 0000000..47f2121
--- /dev/null
+++ b/python/docs/source/index.rst
@@ -0,0 +1,25 @@
+.. majorminer documentation master file
+
+
+Welcome to the documentation of the majorminer research project realized by two students of the DHBW Karlsruhe. This documentation only includes the API for the Python code, NOT the C++ code.
+
+* :ref:`genindex`
+* :ref:`modindex`
+
+
+Overview
+========
+
+.. toctree::
+ :maxdepth: 2
+
+ overview
+
+
+API Reference
+=============
+
+.. toctree::
+ :maxdepth: 2
+
+ api
diff --git a/python/docs/source/modules.rst b/python/docs/source/modules.rst
new file mode 100644
index 0000000..e9ff8ac
--- /dev/null
+++ b/python/docs/source/modules.rst
@@ -0,0 +1,7 @@
+src
+===
+
+.. toctree::
+ :maxdepth: 4
+
+ src
diff --git a/python/docs/source/overview.rst b/python/docs/source/overview.rst
new file mode 100644
index 0000000..0f16241
--- /dev/null
+++ b/python/docs/source/overview.rst
@@ -0,0 +1,21 @@
+.. _overview:
+
+Overview
+========
+
+Goal
+----
+
+.. figure:: /_static/embedding_solver_principle.png
+ :alt: Principle of the embedding solver
+
+ Principle of the embedding solver. Find an embedding for minor H in graph G (in this case: a simple Chimera Graph). Colors indicate different chains (and are not related to the colors in the architecture diagram below).
+
+
+Python architecture
+-------------------
+
+.. figure:: /_static/python_architecture.png
+ :alt: Python architecture
+
+ Simplified overview over the Python architecture. Grey boxes are classes.
\ No newline at end of file
diff --git a/python/docs/source/src.drawing.rst b/python/docs/source/src.drawing.rst
new file mode 100644
index 0000000..6aef7e7
--- /dev/null
+++ b/python/docs/source/src.drawing.rst
@@ -0,0 +1,21 @@
+src.drawing package
+===================
+
+Submodules
+----------
+
+src.drawing.draw module
+-----------------------
+
+.. automodule:: src.drawing.draw
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: src.drawing
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/python/docs/source/src.embedding.rst b/python/docs/source/src.embedding.rst
new file mode 100644
index 0000000..07a6f81
--- /dev/null
+++ b/python/docs/source/src.embedding.rst
@@ -0,0 +1,29 @@
+src.embedding package
+=====================
+
+Submodules
+----------
+
+src.embedding.embedding module
+------------------------------
+
+.. automodule:: src.embedding.embedding
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+src.embedding.graph\_mapping module
+-----------------------------------
+
+.. automodule:: src.embedding.graph_mapping
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: src.embedding
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/python/docs/source/src.graph.rst b/python/docs/source/src.graph.rst
new file mode 100644
index 0000000..c3005ba
--- /dev/null
+++ b/python/docs/source/src.graph.rst
@@ -0,0 +1,29 @@
+src.graph package
+=================
+
+Submodules
+----------
+
+src.graph.chimera\_graph module
+-------------------------------
+
+.. automodule:: src.graph.chimera_graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+src.graph.undirected\_graph module
+----------------------------------
+
+.. automodule:: src.graph.undirected_graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: src.graph
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/python/docs/source/src.rst b/python/docs/source/src.rst
new file mode 100644
index 0000000..c2c6678
--- /dev/null
+++ b/python/docs/source/src.rst
@@ -0,0 +1,21 @@
+src package
+===========
+
+Subpackages
+-----------
+
+.. toctree::
+ :maxdepth: 4
+
+ src.drawing
+ src.embedding
+ src.graph
+ src.solver
+
+Module contents
+---------------
+
+.. automodule:: src
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/python/docs/source/src.solver.rst b/python/docs/source/src.solver.rst
new file mode 100644
index 0000000..022dcf5
--- /dev/null
+++ b/python/docs/source/src.solver.rst
@@ -0,0 +1,37 @@
+src.solver package
+==================
+
+Submodules
+----------
+
+src.solver.embedding\_solver module
+-----------------------------------
+
+.. automodule:: src.solver.embedding_solver
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+src.solver.evolution module
+---------------------------
+
+.. automodule:: src.solver.evolution
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+src.solver.k4\_results module
+-----------------------------
+
+.. automodule:: src.solver.k4_results
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+Module contents
+---------------
+
+.. automodule:: src.solver
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/python/plots/graphs/k_graph.py b/python/plots/graphs/k_graph.py
new file mode 100644
index 0000000..a4786df
--- /dev/null
+++ b/python/plots/graphs/k_graph.py
@@ -0,0 +1,29 @@
+import matplotlib.pyplot as plt
+import networkx as nx
+
+
+def draw_k_graph(n: int):
+ G = nx.complete_graph(n)
+ pos = nx.circular_layout(G)
+
+ fig, ax = plt.subplots(figsize=(5, 5))
+ plt.tight_layout()
+
+ # nx.draw(G)
+ nx.draw_networkx_nodes(G,
+ pos=pos,
+ node_size=500,
+ node_color='#5B5B5B',
+ linewidths=3,
+ edgecolors='#858585')
+ nx.draw_networkx_edges(G,
+ pos=pos,
+ width=2,
+ style='solid',
+ edge_color='#5B5B5B')
+
+ plt.savefig(f'./out/k{i}.pdf', bbox_inches='tight', pad_inches=0)
+
+
+for i in range(1, 41):
+ draw_k_graph(i)
diff --git a/python/plots/how_many_generations/data/evolution_different_probabilities_extend_to_free.py b/python/plots/how_many_generations/data/evolution_different_probabilities_extend_to_free.py
new file mode 100644
index 0000000..73a5d80
--- /dev/null
+++ b/python/plots/how_many_generations/data/evolution_different_probabilities_extend_to_free.py
@@ -0,0 +1,117 @@
+# Move this file to src/solver to start
+
+import logging
+import multiprocessing
+import os
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+import numpy as np
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+max_total = 50
+max_generations = 600
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def different_params():
+ for extend_to_free_probability in np.linspace(0, 1.0, 10):
+ print(f'Started with probability {extend_to_free_probability}')
+ graph = TestGraph.k(8)
+ start_time = time.time()
+ start_multiprocessing((graph, extend_to_free_probability),
+ f'k8_extend_to_free_prob_{extend_to_free_probability}')
+ duration = time.time() - start_time
+ print(f'Duration using probability {extend_to_free_probability}: {duration} s')
+
+
+def start_multiprocessing(plot_params, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 75)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, plot_params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/how_many_generations_{m}x{n}_{max_total}_{max_generations}_max_gen_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(plot_params, j) -> int:
+ solver = EmbeddingSolver(plot_params[0], m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver, plot_params)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver, plot_params) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ evo_params = EvolutionParams(
+ population_size=4,
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=plot_params[1] # should be <=0.5
+ )
+
+ child = solver.generate_population_and_select(evo_params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ different_params()
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.0.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.0.txt
new file mode 100644
index 0000000..cc6b276
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.0.txt
@@ -0,0 +1,50 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+77
+77
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+166
+193
+140
+238
+369
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.11.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.11.txt
new file mode 100644
index 0000000..e51d618
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.11.txt
@@ -0,0 +1,50 @@
+36
+54
+72
+202
+97
+54
+237
+-1
+-1
+195
+90
+71
+66
+115
+111
+146
+15
+17
+225
+44
+347
+110
+52
+79
+125
+141
+95
+201
+87
+71
+30
+111
+72
+43
+109
+93
+67
+236
+475
+155
+176
+161
+50
+71
+25
+188
+210
+-1
+296
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.22.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.22.txt
new file mode 100644
index 0000000..1f62b11
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.22.txt
@@ -0,0 +1,50 @@
+41
+80
+135
+130
+238
+119
+207
+298
+49
+180
+160
+566
+226
+63
+74
+-1
+108
+346
+78
+63
+87
+160
+99
+315
+33
+425
+-1
+46
+100
+125
+43
+-1
+116
+111
+-1
+238
+99
+122
+298
+113
+44
+369
+-1
+106
+67
+540
+352
+-1
+-1
+539
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.33.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.33.txt
new file mode 100644
index 0000000..b8ea03c
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.33.txt
@@ -0,0 +1,50 @@
+77
+90
+77
+169
+160
+261
+31
+168
+217
+204
+245
+388
+175
+233
+65
+91
+232
+79
+181
+168
+114
+49
+14
+292
+186
+44
+191
+207
+35
+222
+-1
+230
+56
+217
+181
+51
+160
+109
+25
+-1
+147
+222
+-1
+61
+31
+80
+-1
+115
+339
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.44.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.44.txt
new file mode 100644
index 0000000..568a5bb
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.44.txt
@@ -0,0 +1,50 @@
+138
+149
+185
+70
+59
+286
+153
+47
+36
+59
+17
+-1
+530
+-1
+66
+17
+116
+84
+64
+16
+76
+-1
+27
+227
+-1
+477
+47
+75
+185
+304
+188
+247
+-1
+120
+186
+115
+50
+55
+250
+156
+313
+97
+146
+47
+82
+-1
+418
+442
+-1
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.56.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.56.txt
new file mode 100644
index 0000000..0add582
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.56.txt
@@ -0,0 +1,50 @@
+45
+70
+138
+174
+71
+229
+134
+52
+111
+200
+46
+74
+344
+161
+342
+171
+228
+195
+-1
+37
+249
+45
+153
+72
+58
+88
+250
+264
+89
+380
+42
+252
+-1
+-1
+30
+381
+159
+94
+241
+187
+57
+154
+-1
+143
+236
+-1
+163
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.67.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.67.txt
new file mode 100644
index 0000000..431f4d0
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.67.txt
@@ -0,0 +1,50 @@
+68
+168
+193
+15
+141
+80
+210
+105
+105
+334
+-1
+321
+435
+185
+369
+232
+236
+138
+137
+-1
+29
+133
+199
+-1
+138
+15
+204
+29
+148
+102
+156
+234
+-1
+132
+-1
+68
+273
+147
+-1
+54
+464
+203
+176
+84
+176
+-1
+279
+-1
+568
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.78.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.78.txt
new file mode 100644
index 0000000..3972e56
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.78.txt
@@ -0,0 +1,50 @@
+14
+149
+282
+-1
+260
+161
+-1
+16
+78
+479
+278
+55
+143
+89
+-1
+122
+170
+-1
+15
+19
+54
+-1
+-1
+86
+296
+62
+303
+497
+535
+251
+-1
+476
+-1
+-1
+88
+298
+125
+45
+42
+-1
+162
+-1
+79
+36
+47
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.89.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.89.txt
new file mode 100644
index 0000000..6e28c9f
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_0.89.txt
@@ -0,0 +1,50 @@
+53
+99
+113
+148
+52
+180
+258
+245
+165
+-1
+-1
+305
+594
+-1
+-1
+21
+259
+249
+-1
+100
+76
+332
+390
+362
+-1
+98
+513
+292
+233
+194
+329
+-1
+41
+72
+-1
+-1
+-1
+101
+30
+279
+229
+-1
+216
+-1
+-1
+-1
+-1
+306
+423
+-1
diff --git a/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_1.0.txt b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_1.0.txt
new file mode 100644
index 0000000..fa21d68
--- /dev/null
+++ b/python/plots/how_many_generations/data/extend_to_free_prob_50_runs/how_many_generations_5x5_50_600_max_gen_k8_extend_to_free_prob_1.0.txt
@@ -0,0 +1,50 @@
+28
+242
+254
+287
+-1
+-1
+440
+-1
+-1
+182
+-1
+88
+-1
+-1
+89
+417
+121
+52
+-1
+270
+489
+-1
+-1
+253
+87
+302
+250
+-1
+-1
+-1
+57
+-1
+357
+-1
+-1
+-1
+-1
+23
+290
+-1
+15
+239
+-1
+514
+296
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k10.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k10.txt
new file mode 100644
index 0000000..033cb5b
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k10.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k2.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k2.txt
new file mode 100644
index 0000000..257325e
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k2.txt
@@ -0,0 +1,1000 @@
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k3.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k3.txt
new file mode 100644
index 0000000..eb657d0
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k3.txt
@@ -0,0 +1,1000 @@
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+1
+3
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+5
+3
+1
+1
+1
+1
+1
+5
+1
+1
+1
+1
+1
+1
+4
+4
+4
+1
+4
+1
+1
+3
+4
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+6
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+4
+1
+3
+1
+1
+1
+1
+1
+7
+4
+1
+1
+1
+1
+10
+1
+1
+1
+1
+3
+1
+5
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+4
+1
+3
+1
+5
+1
+1
+1
+1
+1
+1
+5
+4
+3
+1
+1
+1
+5
+1
+1
+4
+1
+6
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+5
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+5
+1
+3
+5
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+1
+1
+1
+1
+1
+1
+1
+1
+3
+4
+1
+1
+1
+1
+5
+1
+1
+1
+8
+1
+5
+3
+1
+1
+1
+1
+1
+4
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+5
+1
+1
+1
+3
+1
+4
+1
+1
+1
+1
+1
+3
+5
+1
+1
+4
+1
+1
+4
+3
+1
+1
+1
+3
+1
+1
+1
+1
+1
+4
+5
+1
+1
+9
+1
+1
+1
+1
+1
+1
+1
+5
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+9
+1
+3
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+1
+5
+1
+3
+1
+1
+1
+1
+5
+1
+1
+1
+6
+1
+1
+1
+1
+1
+4
+5
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+6
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+6
+1
+3
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+6
+1
+1
+1
+5
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+5
+1
+1
+4
+3
+1
+1
+1
+1
+1
+1
+3
+7
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+6
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+4
+1
+1
+3
+3
+1
+1
+8
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+4
+1
+4
+1
+1
+1
+1
+1
+1
+1
+7
+1
+4
+4
+1
+3
+1
+4
+3
+1
+1
+1
+1
+3
+1
+5
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+2
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+5
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+8
+1
+3
+1
+1
+1
+1
+1
+1
+4
+5
+1
+1
+1
+1
+4
+1
+3
+1
+1
+1
+1
+1
+3
+4
+3
+1
+3
+1
+1
+1
+1
+1
+1
+1
+5
+1
+1
+3
+4
+1
+1
+5
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+5
+6
+3
+1
+4
+1
+1
+1
+1
+1
+1
+4
+5
+1
+1
+1
+1
+1
+1
+3
+3
+1
+1
+8
+1
+1
+6
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+8
+1
+1
+1
+5
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+4
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+5
+3
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+4
+5
+3
+1
+1
+1
+3
+3
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+4
+3
+1
+1
+1
+4
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+3
+14
+4
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+6
+1
+1
+1
+3
+1
+3
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+1
+1
+1
+1
+4
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+8
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+4
+1
+3
+1
+1
+4
+1
+5
+3
+12
+1
+3
+9
+1
+1
+1
+1
+5
+1
+1
+1
+1
+3
+3
+1
+3
+3
+1
+1
+1
+1
+1
+4
+1
+1
+1
+7
+1
+6
+3
+1
+1
+4
+1
+1
+1
+1
+1
+4
+1
+4
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k4.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k4.txt
new file mode 100644
index 0000000..44f41eb
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k4.txt
@@ -0,0 +1,1000 @@
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+2
+2
+8
+2
+2
+2
+2
+2
+5
+2
+2
+9
+2
+2
+2
+2
+11
+2
+2
+10
+2
+2
+2
+2
+2
+2
+8
+5
+2
+2
+2
+5
+2
+10
+2
+12
+2
+7
+2
+2
+2
+2
+5
+2
+9
+12
+10
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+10
+7
+2
+14
+2
+10
+2
+2
+5
+15
+2
+2
+2
+2
+19
+9
+2
+2
+2
+3
+2
+2
+2
+2
+2
+2
+11
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+2
+9
+7
+2
+2
+2
+13
+2
+2
+3
+7
+5
+7
+2
+11
+2
+2
+15
+13
+2
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+7
+2
+2
+8
+2
+9
+2
+2
+2
+2
+2
+10
+2
+2
+6
+2
+2
+2
+2
+2
+2
+6
+2
+2
+6
+2
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+6
+9
+7
+2
+2
+2
+2
+2
+8
+2
+6
+2
+2
+2
+2
+2
+9
+2
+9
+2
+2
+2
+2
+16
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+14
+2
+2
+10
+2
+9
+2
+8
+2
+2
+2
+2
+2
+2
+2
+2
+2
+10
+9
+2
+2
+9
+12
+2
+2
+2
+2
+2
+2
+2
+10
+2
+2
+2
+2
+20
+2
+16
+7
+11
+7
+2
+2
+2
+15
+6
+2
+8
+8
+2
+2
+5
+7
+2
+5
+2
+2
+2
+2
+2
+2
+2
+12
+14
+2
+2
+2
+2
+2
+2
+5
+2
+2
+2
+2
+6
+2
+2
+2
+2
+2
+7
+18
+18
+2
+2
+2
+2
+2
+2
+10
+2
+2
+7
+2
+2
+3
+2
+2
+2
+8
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+8
+2
+2
+2
+2
+2
+7
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+9
+6
+6
+2
+2
+2
+2
+2
+2
+2
+2
+2
+18
+2
+10
+7
+2
+2
+10
+2
+10
+2
+2
+2
+2
+13
+2
+2
+2
+8
+7
+2
+11
+2
+2
+2
+2
+2
+8
+7
+2
+2
+2
+8
+8
+2
+9
+2
+2
+2
+2
+12
+2
+2
+7
+2
+2
+6
+6
+2
+2
+2
+2
+2
+7
+2
+2
+2
+10
+6
+7
+2
+2
+2
+2
+11
+2
+2
+2
+9
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+21
+8
+6
+2
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+2
+2
+2
+2
+3
+9
+2
+2
+11
+2
+11
+2
+2
+2
+2
+8
+13
+2
+2
+7
+2
+2
+2
+5
+2
+12
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+6
+2
+2
+6
+2
+11
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+2
+2
+7
+2
+2
+2
+15
+20
+6
+2
+2
+2
+2
+2
+2
+2
+2
+2
+9
+7
+2
+2
+2
+2
+2
+6
+2
+2
+2
+2
+19
+2
+2
+9
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+5
+13
+2
+2
+2
+9
+2
+2
+2
+2
+8
+2
+2
+2
+2
+12
+6
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+2
+2
+9
+2
+2
+2
+2
+2
+6
+2
+12
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+17
+2
+2
+9
+2
+2
+6
+2
+2
+2
+2
+2
+2
+2
+17
+2
+8
+2
+3
+2
+2
+11
+2
+2
+2
+9
+2
+2
+2
+5
+6
+2
+2
+2
+11
+2
+2
+16
+2
+2
+2
+2
+2
+10
+2
+2
+7
+8
+14
+2
+2
+2
+2
+15
+2
+8
+2
+2
+2
+7
+2
+2
+17
+2
+5
+2
+8
+2
+2
+2
+3
+2
+2
+2
+9
+2
+2
+2
+5
+2
+23
+2
+3
+2
+2
+17
+11
+2
+2
+2
+2
+9
+2
+7
+2
+2
+2
+2
+2
+10
+2
+2
+2
+2
+2
+9
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+2
+2
+6
+2
+2
+2
+2
+2
+2
+2
+11
+2
+2
+2
+2
+2
+8
+2
+2
+2
+2
+6
+2
+2
+2
+2
+2
+2
+2
+8
+14
+7
+2
+12
+5
+7
+2
+2
+2
+2
+2
+2
+15
+2
+18
+2
+11
+2
+2
+7
+11
+12
+2
+2
+2
+16
+2
+2
+10
+2
+2
+2
+2
+11
+2
+9
+7
+2
+2
+8
+2
+2
+2
+2
+2
+2
+2
+11
+2
+2
+8
+2
+2
+9
+2
+6
+2
+2
+2
+2
+11
+2
+2
+7
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+11
+12
+2
+12
+7
+2
+4
+2
+2
+2
+2
+6
+8
+7
+2
+2
+8
+5
+2
+2
+2
+2
+2
+21
+2
+2
+2
+6
+2
+2
+12
+10
+6
+3
+8
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+14
+2
+2
+2
+7
+9
+2
+2
+2
+17
+2
+2
+2
+17
+18
+2
+2
+2
+12
+2
+14
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+2
+12
+6
+2
+2
+2
+2
+2
+7
+17
+2
+2
+8
+2
+2
+2
+6
+2
+2
+2
+2
+2
+8
+12
+2
+7
+2
+2
+2
+2
+2
+6
+2
+2
+2
+5
+2
+2
+2
+2
+2
+7
+2
+2
+2
+2
+8
+2
+2
+2
+2
+2
+6
+29
+13
+2
+2
+8
+7
+19
+19
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k5.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k5.txt
new file mode 100644
index 0000000..5a76cbe
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k5.txt
@@ -0,0 +1,1000 @@
+2
+4
+3
+4
+3
+10
+9
+5
+4
+16
+3
+10
+16
+16
+5
+9
+3
+22
+12
+8
+3
+3
+13
+5
+9
+5
+14
+27
+20
+4
+3
+6
+6
+31
+3
+17
+3
+3
+8
+10
+3
+3
+3
+3
+3
+12
+9
+6
+8
+16
+3
+12
+4
+11
+20
+14
+3
+3
+3
+2
+3
+3
+3
+10
+12
+12
+8
+3
+14
+17
+10
+3
+3
+3
+14
+3
+11
+3
+3
+3
+12
+10
+6
+3
+15
+5
+4
+3
+11
+3
+15
+11
+3
+7
+3
+8
+15
+3
+3
+3
+5
+3
+3
+3
+3
+3
+3
+19
+3
+3
+11
+3
+12
+10
+3
+7
+18
+3
+3
+17
+3
+3
+19
+3
+2
+3
+9
+4
+2
+3
+8
+15
+3
+19
+33
+16
+9
+20
+9
+3
+3
+21
+3
+3
+7
+22
+9
+13
+3
+3
+27
+3
+13
+5
+23
+3
+15
+3
+3
+2
+12
+3
+12
+6
+9
+5
+3
+7
+8
+8
+3
+3
+3
+3
+8
+12
+3
+3
+3
+12
+3
+4
+17
+3
+3
+3
+2
+9
+3
+12
+3
+9
+2
+9
+13
+10
+4
+3
+18
+8
+8
+9
+14
+3
+13
+18
+32
+5
+3
+14
+20
+25
+9
+12
+23
+3
+22
+17
+3
+3
+9
+10
+11
+3
+3
+4
+10
+4
+20
+2
+3
+3
+22
+3
+19
+3
+41
+16
+3
+5
+3
+13
+22
+9
+17
+32
+5
+3
+3
+14
+3
+3
+8
+2
+3
+12
+4
+3
+10
+22
+10
+5
+9
+7
+3
+3
+3
+3
+3
+9
+15
+3
+7
+3
+5
+5
+8
+13
+3
+6
+3
+18
+3
+11
+3
+14
+17
+22
+20
+4
+3
+8
+5
+3
+4
+4
+14
+2
+18
+3
+10
+3
+3
+3
+3
+5
+4
+13
+12
+10
+8
+3
+17
+16
+3
+15
+12
+10
+7
+3
+3
+2
+8
+13
+3
+10
+3
+5
+3
+3
+8
+19
+3
+2
+9
+14
+3
+3
+13
+3
+3
+3
+3
+4
+13
+14
+2
+11
+3
+3
+3
+3
+3
+2
+11
+7
+9
+3
+15
+5
+5
+3
+3
+3
+3
+3
+3
+5
+3
+12
+11
+3
+7
+5
+3
+4
+8
+4
+2
+3
+23
+5
+3
+4
+3
+14
+14
+20
+3
+9
+3
+3
+4
+3
+2
+4
+11
+11
+12
+3
+4
+8
+3
+6
+17
+3
+3
+3
+3
+11
+3
+3
+3
+5
+3
+3
+3
+13
+3
+8
+19
+3
+15
+7
+3
+3
+9
+3
+5
+3
+9
+33
+3
+3
+3
+21
+13
+3
+3
+11
+2
+10
+3
+12
+3
+8
+3
+3
+5
+3
+3
+3
+3
+3
+4
+7
+21
+15
+3
+3
+3
+11
+4
+5
+10
+3
+3
+14
+3
+2
+11
+3
+25
+5
+2
+9
+9
+2
+21
+3
+13
+3
+7
+19
+3
+14
+8
+9
+18
+9
+3
+8
+3
+11
+4
+3
+4
+3
+3
+3
+5
+7
+8
+21
+9
+3
+3
+5
+3
+3
+3
+5
+3
+10
+8
+11
+3
+4
+7
+7
+4
+3
+3
+12
+3
+3
+3
+3
+3
+9
+11
+3
+9
+12
+13
+3
+4
+4
+3
+8
+3
+9
+2
+3
+3
+20
+17
+3
+16
+9
+3
+16
+9
+6
+3
+9
+3
+3
+14
+3
+11
+3
+25
+3
+3
+4
+14
+16
+3
+3
+2
+3
+3
+3
+9
+23
+5
+5
+18
+3
+15
+15
+3
+3
+5
+12
+2
+3
+3
+10
+3
+18
+28
+3
+14
+26
+9
+17
+12
+18
+2
+12
+17
+14
+3
+7
+3
+6
+2
+2
+3
+16
+18
+11
+27
+10
+3
+3
+3
+6
+6
+8
+3
+5
+19
+15
+3
+3
+12
+16
+3
+14
+14
+3
+3
+3
+5
+3
+14
+3
+5
+2
+3
+3
+2
+12
+3
+12
+4
+15
+9
+4
+10
+23
+15
+3
+2
+3
+20
+3
+3
+4
+3
+15
+2
+7
+3
+4
+15
+3
+17
+3
+3
+9
+5
+3
+15
+3
+3
+17
+3
+3
+3
+3
+12
+4
+19
+2
+19
+2
+8
+9
+10
+3
+9
+12
+7
+12
+4
+14
+17
+3
+18
+10
+17
+23
+12
+12
+3
+10
+3
+6
+14
+11
+8
+10
+3
+3
+3
+7
+3
+10
+5
+5
+3
+12
+3
+3
+3
+4
+3
+3
+3
+9
+3
+13
+10
+3
+3
+3
+16
+3
+3
+29
+3
+8
+3
+3
+10
+3
+3
+3
+11
+5
+8
+3
+6
+9
+2
+18
+3
+13
+3
+3
+15
+12
+12
+3
+2
+10
+8
+8
+15
+3
+3
+16
+15
+17
+3
+2
+12
+3
+3
+4
+13
+16
+3
+3
+3
+12
+3
+3
+15
+3
+3
+12
+4
+14
+18
+3
+18
+3
+3
+16
+22
+3
+9
+17
+11
+19
+15
+14
+21
+5
+7
+3
+3
+5
+7
+11
+10
+16
+8
+5
+3
+9
+7
+11
+3
+4
+3
+15
+25
+3
+3
+9
+24
+12
+3
+3
+11
+8
+3
+3
+5
+20
+3
+2
+3
+4
+20
+11
+17
+3
+13
+11
+5
+18
+3
+8
+23
+10
+2
+3
+4
+3
+3
+22
+3
+3
+7
+5
+12
+3
+3
+3
+3
+3
+17
+3
+3
+2
+6
+3
+3
+13
+3
+19
+3
+13
+15
+13
+3
+21
+19
+3
+3
+3
+16
+5
+7
+3
+12
+13
+5
+3
+15
+10
+13
+3
+3
+3
+4
+3
+13
+14
+11
+13
+3
+3
+4
+7
+3
+3
+10
+4
+5
+9
+7
+5
+47
+3
+11
+3
+5
+5
+5
+3
+11
+8
+4
+7
+10
+3
+3
+8
+27
+9
+10
+3
+12
+14
+13
+12
+3
+11
+15
+17
+3
+3
+22
+3
+3
+4
+14
+5
+6
+14
+8
+17
+2
+3
+3
+3
+3
+9
+4
+3
+23
+3
+7
+3
+3
+53
+3
+3
+18
+6
+3
+4
+6
+7
+3
+23
+5
+3
+15
+16
+15
+25
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k6.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k6.txt
new file mode 100644
index 0000000..9c65b45
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k6.txt
@@ -0,0 +1,1000 @@
+9
+11
+15
+21
+18
+17
+16
+27
+23
+19
+15
+21
+9
+20
+10
+8
+39
+8
+9
+12
+11
+17
+12
+17
+23
+25
+9
+14
+14
+14
+26
+10
+14
+37
+14
+26
+16
+27
+16
+20
+15
+25
+18
+11
+14
+18
+10
+42
+22
+7
+15
+12
+9
+14
+29
+22
+7
+10
+7
+8
+21
+10
+31
+17
+17
+10
+14
+15
+12
+11
+28
+16
+16
+12
+22
+8
+18
+52
+14
+19
+8
+10
+17
+15
+36
+31
+12
+22
+37
+10
+27
+11
+11
+15
+72
+13
+13
+15
+10
+18
+55
+31
+10
+22
+8
+18
+17
+16
+12
+11
+35
+8
+11
+16
+11
+10
+9
+10
+16
+13
+39
+19
+12
+17
+15
+17
+19
+15
+18
+15
+18
+16
+11
+23
+8
+14
+15
+12
+12
+8
+25
+7
+20
+11
+13
+19
+22
+13
+14
+50
+10
+26
+22
+8
+13
+19
+43
+11
+21
+22
+12
+11
+24
+12
+13
+17
+11
+9
+22
+18
+8
+19
+10
+18
+8
+74
+12
+16
+11
+34
+9
+12
+10
+10
+18
+11
+16
+30
+9
+26
+23
+7
+14
+23
+26
+10
+11
+10
+26
+9
+13
+8
+17
+10
+9
+18
+15
+16
+14
+35
+11
+10
+27
+11
+17
+10
+11
+25
+10
+8
+10
+29
+11
+13
+11
+12
+24
+10
+21
+12
+9
+10
+13
+20
+18
+29
+19
+41
+11
+9
+19
+-1
+12
+16
+23
+25
+20
+8
+11
+11
+8
+12
+8
+8
+50
+8
+25
+94
+20
+7
+35
+15
+11
+9
+22
+10
+9
+9
+13
+10
+16
+19
+15
+11
+15
+16
+16
+12
+9
+16
+10
+31
+14
+8
+20
+12
+13
+10
+11
+10
+19
+9
+55
+15
+18
+8
+11
+10
+8
+9
+28
+8
+12
+18
+22
+9
+17
+19
+9
+12
+9
+23
+12
+15
+15
+16
+19
+10
+9
+17
+17
+8
+10
+11
+18
+14
+7
+23
+7
+54
+10
+21
+15
+33
+13
+10
+30
+26
+14
+19
+25
+12
+17
+36
+12
+7
+12
+20
+22
+9
+17
+14
+15
+10
+17
+14
+31
+10
+9
+13
+9
+36
+16
+26
+8
+16
+18
+21
+23
+27
+40
+8
+19
+17
+9
+23
+14
+14
+8
+25
+8
+14
+13
+10
+26
+8
+14
+10
+10
+15
+9
+76
+17
+20
+15
+7
+47
+21
+30
+15
+14
+9
+13
+8
+9
+14
+25
+17
+52
+18
+30
+8
+38
+42
+12
+14
+13
+9
+17
+11
+14
+9
+16
+12
+12
+18
+9
+11
+19
+23
+13
+18
+27
+24
+10
+26
+10
+11
+9
+22
+-1
+10
+9
+10
+11
+8
+17
+14
+21
+16
+10
+10
+11
+14
+14
+17
+9
+17
+13
+9
+9
+21
+18
+9
+19
+16
+13
+51
+10
+13
+10
+13
+18
+11
+17
+8
+11
+8
+11
+9
+9
+11
+7
+12
+16
+11
+15
+35
+12
+8
+27
+14
+12
+21
+33
+16
+7
+12
+17
+11
+8
+20
+21
+24
+8
+11
+13
+24
+10
+54
+8
+31
+10
+7
+15
+10
+14
+10
+9
+66
+22
+31
+26
+11
+12
+14
+8
+35
+17
+16
+11
+8
+11
+16
+22
+15
+11
+13
+12
+10
+17
+8
+14
+18
+11
+16
+10
+13
+12
+27
+15
+21
+8
+8
+18
+18
+28
+9
+7
+16
+30
+23
+18
+15
+8
+8
+7
+15
+12
+19
+12
+24
+17
+14
+17
+14
+17
+17
+11
+10
+9
+10
+16
+16
+13
+15
+14
+14
+40
+7
+9
+11
+13
+24
+11
+9
+23
+9
+13
+21
+12
+23
+19
+12
+10
+8
+8
+25
+11
+10
+10
+9
+19
+8
+35
+25
+22
+9
+15
+15
+10
+8
+32
+18
+15
+18
+10
+12
+12
+7
+10
+21
+18
+10
+10
+9
+16
+13
+13
+14
+14
+17
+9
+12
+10
+14
+22
+10
+34
+14
+13
+8
+14
+14
+8
+23
+18
+22
+38
+13
+32
+9
+10
+23
+7
+32
+16
+15
+23
+8
+7
+10
+49
+10
+10
+14
+13
+9
+25
+16
+24
+16
+17
+13
+15
+15
+20
+28
+15
+9
+23
+8
+16
+41
+16
+31
+18
+26
+10
+21
+8
+7
+12
+9
+13
+18
+67
+11
+10
+16
+19
+15
+12
+19
+16
+14
+28
+23
+9
+12
+10
+22
+16
+9
+19
+22
+12
+12
+10
+15
+12
+19
+8
+14
+27
+13
+23
+15
+14
+14
+9
+-1
+8
+28
+12
+8
+20
+13
+15
+8
+15
+7
+15
+24
+24
+20
+12
+9
+18
+15
+12
+17
+8
+23
+13
+28
+16
+13
+12
+99
+7
+15
+26
+16
+9
+12
+30
+24
+12
+15
+11
+23
+14
+13
+8
+9
+17
+10
+9
+10
+10
+8
+11
+25
+22
+10
+19
+20
+23
+12
+21
+50
+19
+8
+31
+59
+13
+14
+32
+10
+8
+8
+16
+12
+30
+10
+14
+10
+12
+17
+7
+13
+17
+28
+25
+8
+14
+10
+21
+13
+27
+17
+14
+26
+8
+9
+15
+16
+19
+51
+10
+23
+13
+12
+9
+7
+8
+9
+14
+12
+17
+14
+-1
+20
+22
+25
+14
+9
+22
+10
+20
+7
+12
+14
+16
+25
+13
+10
+9
+10
+9
+13
+9
+22
+13
+21
+14
+8
+12
+14
+24
+10
+14
+22
+16
+12
+27
+14
+13
+13
+9
+8
+10
+22
+18
+32
+16
+16
+7
+19
+16
+20
+24
+23
+16
+20
+25
+18
+15
+11
+9
+11
+42
+10
+8
+15
+22
+14
+13
+14
+12
+13
+10
+11
+21
+11
+19
+8
+16
+9
+33
+12
+11
+9
+31
+14
+30
+10
+12
+10
+13
+20
+8
+9
+10
+13
+16
+13
+17
+10
+8
+16
+15
+10
+14
+12
+10
+13
+15
+54
+9
+17
+14
+7
+10
+19
+14
+12
+17
+17
+7
+10
+46
+24
+11
+47
+9
+9
+13
+21
+19
+25
+18
+9
+11
+10
+14
+7
+8
+13
+8
+13
+12
+14
+24
+17
+11
+34
+36
+97
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k7.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k7.txt
new file mode 100644
index 0000000..f60a9a6
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k7.txt
@@ -0,0 +1,1000 @@
+15
+14
+16
+18
+20
+25
+11
+18
+17
+19
+42
+19
+17
+18
+29
+15
+10
+15
+-1
+17
+22
+23
+66
+37
+19
+17
+23
+24
+31
+23
+21
+14
+52
+26
+12
+14
+20
+21
+20
+25
+-1
+14
+13
+14
+16
+11
+-1
+9
+51
+25
+33
+21
+11
+13
+18
+32
+20
+26
+26
+19
+21
+-1
+16
+39
+14
+19
+16
+19
+17
+17
+-1
+40
+27
+16
+11
+15
+34
+20
+-1
+18
+29
+11
+14
+36
+-1
+29
+19
+15
+44
+14
+29
+13
+15
+21
+23
+18
+21
+13
+24
+16
+34
+13
+17
+13
+17
+-1
+18
+14
+24
+19
+16
+25
+36
+13
+20
+18
+12
+34
+14
+20
+16
+12
+14
+19
+39
+29
+11
+14
+20
+15
+22
+22
+24
+38
+23
+16
+17
+42
+82
+42
+18
+18
+25
+15
+28
+53
+-1
+27
+14
+19
+24
+27
+24
+19
+-1
+22
+17
+34
+-1
+19
+12
+29
+52
+37
+16
+20
+24
+-1
+69
+-1
+35
+13
+26
+19
+39
+20
+33
+15
+18
+34
+15
+20
+15
+19
+15
+20
+15
+15
+17
+21
+47
+12
+19
+22
+16
+16
+-1
+-1
+17
+-1
+51
+19
+36
+14
+11
+18
+58
+18
+26
+52
+34
+14
+16
+17
+16
+31
+16
+29
+12
+11
+14
+78
+29
+11
+24
+-1
+25
+21
+17
+39
+17
+46
+19
+12
+38
+12
+20
+69
+-1
+16
+-1
+20
+20
+19
+12
+11
+-1
+67
+20
+17
+13
+19
+30
+16
+27
+-1
+18
+14
+22
+22
+24
+15
+13
+13
+10
+40
+13
+15
+13
+22
+17
+24
+25
+23
+19
+50
+18
+23
+15
+14
+16
+28
+20
+15
+15
+14
+31
+16
+29
+12
+15
+56
+13
+21
+17
+17
+22
+31
+14
+21
+14
+13
+-1
+22
+31
+-1
+15
+-1
+54
+16
+13
+-1
+-1
+26
+16
+84
+21
+22
+21
+15
+14
+21
+27
+14
+24
+24
+18
+20
+14
+12
+26
+14
+15
+23
+27
+82
+17
+21
+26
+28
+16
+19
+16
+13
+10
+28
+32
+57
+24
+21
+22
+27
+-1
+24
+12
+23
+27
+-1
+18
+50
+22
+57
+24
+17
+36
+22
+14
+-1
+35
+18
+24
+12
+14
+14
+23
+21
+36
+29
+23
+24
+-1
+25
+13
+-1
+11
+14
+13
+-1
+17
+18
+-1
+11
+23
+44
+15
+19
+12
+32
+25
+22
+14
+23
+-1
+20
+47
+17
+21
+14
+-1
+-1
+27
+10
+31
+37
+21
+16
+13
+24
+11
+-1
+20
+9
+15
+26
+15
+11
+15
+11
+13
+-1
+35
+15
+16
+-1
+23
+-1
+15
+19
+19
+12
+19
+14
+23
+23
+38
+12
+16
+17
+17
+24
+34
+22
+22
+17
+24
+19
+12
+13
+16
+15
+16
+18
+54
+34
+14
+29
+12
+64
+70
+17
+13
+23
+11
+15
+15
+42
+24
+73
+16
+16
+24
+10
+21
+28
+24
+48
+23
+30
+16
+-1
+11
+18
+29
+29
+-1
+13
+21
+29
+23
+-1
+24
+24
+16
+13
+-1
+14
+22
+16
+33
+11
+34
+15
+16
+26
+18
+18
+13
+21
+11
+-1
+14
+32
+-1
+29
+19
+25
+19
+15
+26
+16
+27
+16
+26
+10
+38
+-1
+19
+22
+14
+26
+13
+30
+-1
+13
+23
+-1
+26
+19
+36
+23
+33
+-1
+-1
+16
+-1
+11
+9
+17
+-1
+18
+25
+21
+21
+14
+41
+78
+27
+19
+25
+26
+19
+12
+22
+18
+23
+64
+20
+23
+17
+23
+17
+40
+11
+17
+20
+26
+13
+-1
+24
+28
+56
+18
+14
+24
+12
+15
+21
+-1
+-1
+14
+-1
+30
+29
+31
+-1
+25
+14
+25
+79
+12
+14
+16
+-1
+21
+51
+13
+15
+16
+25
+39
+13
+31
+16
+-1
+45
+17
+20
+47
+23
+13
+24
+14
+12
+18
+18
+23
+11
+11
+32
+20
+12
+29
+22
+-1
+19
+21
+18
+48
+22
+28
+27
+34
+15
+16
+28
+36
+13
+32
+36
+-1
+18
+12
+15
+12
+20
+50
+20
+13
+21
+12
+10
+22
+-1
+16
+14
+18
+17
+22
+22
+28
+23
+-1
+-1
+34
+-1
+63
+19
+17
+28
+18
+28
+-1
+-1
+27
+29
+-1
+71
+17
+42
+29
+13
+30
+35
+10
+15
+15
+19
+21
+19
+24
+38
+21
+72
+92
+19
+25
+14
+68
+23
+-1
+19
+18
+12
+18
+31
+20
+12
+14
+12
+-1
+-1
+17
+29
+22
+12
+32
+11
+20
+47
+20
+38
+18
+19
+12
+75
+37
+17
+18
+15
+20
+16
+15
+19
+18
+46
+15
+20
+17
+25
+11
+16
+27
+42
+14
+19
+19
+22
+13
+19
+22
+18
+-1
+14
+17
+18
+20
+14
+18
+-1
+24
+17
+14
+-1
+23
+16
+13
+16
+17
+-1
+28
+28
+17
+46
+-1
+13
+20
+-1
+29
+55
+16
+45
+13
+30
+24
+11
+17
+18
+31
+14
+21
+11
+29
+15
+25
+21
+24
+42
+23
+12
+-1
+18
+13
+14
+-1
+18
+24
+11
+21
+14
+16
+29
+16
+27
+22
+11
+-1
+25
+19
+25
+-1
+19
+12
+21
+16
+12
+17
+33
+12
+-1
+15
+12
+29
+30
+78
+11
+12
+11
+21
+21
+20
+67
+29
+12
+14
+18
+16
+-1
+13
+19
+18
+19
+57
+20
+24
+21
+20
+17
+22
+-1
+-1
+17
+18
+31
+60
+13
+23
+16
+25
+19
+16
+10
+16
+37
+21
+-1
+18
+26
+14
+19
+13
+45
+78
+13
+33
+25
+18
+13
+21
+16
+20
+25
+13
+15
+21
+29
+22
+17
+16
+21
+60
+15
+23
+30
+27
+40
+33
+-1
+42
+18
+17
+22
+20
+14
+25
+26
+-1
+12
+17
+23
+82
+15
+32
+14
+25
+17
+-1
+13
+33
+25
+12
+20
+-1
+20
+15
+37
+18
+15
+20
+15
+17
+11
+36
+17
+42
+21
+26
+22
+18
+13
+14
+14
+18
+21
+14
+-1
+11
+-1
+19
+25
+22
+19
+12
+-1
+19
+29
+20
+16
+21
+14
+14
+-1
+35
+12
+16
+21
+32
+43
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8.txt
new file mode 100644
index 0000000..02ad689
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8.txt
@@ -0,0 +1,1000 @@
+21
+21
+22
+33
+23
+42
+35
+26
+72
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+64
+-1
+-1
+25
+-1
+-1
+14
+-1
+-1
+17
+-1
+15
+-1
+66
+-1
+-1
+21
+-1
+19
+17
+61
+-1
+-1
+-1
+24
+16
+24
+18
+-1
+26
+-1
+25
+16
+26
+24
+26
+22
+-1
+-1
+-1
+-1
+29
+21
+-1
+28
+22
+45
+52
+-1
+25
+-1
+-1
+24
+-1
+16
+23
+-1
+33
+17
+-1
+16
+-1
+-1
+-1
+17
+-1
+23
+-1
+-1
+49
+25
+41
+-1
+39
+21
+24
+23
+15
+-1
+25
+40
+18
+-1
+-1
+-1
+-1
+-1
+40
+-1
+-1
+-1
+22
+-1
+-1
+24
+-1
+-1
+20
+21
+-1
+-1
+23
+36
+21
+-1
+28
+-1
+24
+-1
+-1
+-1
+28
+-1
+-1
+-1
+34
+-1
+23
+-1
+-1
+-1
+-1
+-1
+38
+32
+-1
+-1
+-1
+22
+34
+-1
+-1
+-1
+-1
+23
+33
+15
+-1
+22
+-1
+30
+-1
+25
+25
+21
+15
+25
+32
+-1
+73
+26
+31
+23
+-1
+-1
+-1
+28
+-1
+18
+-1
+-1
+-1
+40
+50
+13
+-1
+21
+-1
+15
+60
+31
+-1
+24
+22
+-1
+25
+41
+-1
+-1
+22
+-1
+31
+-1
+34
+39
+-1
+-1
+42
+21
+23
+-1
+53
+-1
+-1
+-1
+-1
+26
+-1
+-1
+-1
+-1
+-1
+26
+-1
+-1
+22
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+28
+19
+60
+23
+-1
+31
+30
+-1
+-1
+-1
+-1
+32
+18
+-1
+-1
+-1
+88
+-1
+-1
+46
+15
+20
+-1
+-1
+39
+-1
+-1
+-1
+-1
+18
+61
+30
+-1
+-1
+22
+-1
+-1
+-1
+-1
+17
+-1
+18
+15
+-1
+35
+-1
+-1
+-1
+-1
+32
+23
+-1
+65
+21
+-1
+33
+26
+-1
+-1
+-1
+24
+-1
+-1
+21
+-1
+24
+44
+19
+25
+23
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+42
+-1
+15
+25
+17
+44
+22
+19
+-1
+-1
+-1
+-1
+18
+-1
+-1
+-1
+34
+-1
+15
+26
+-1
+23
+-1
+-1
+-1
+23
+32
+20
+-1
+24
+-1
+20
+-1
+32
+-1
+20
+-1
+20
+-1
+-1
+-1
+31
+43
+-1
+-1
+-1
+40
+-1
+-1
+-1
+-1
+37
+25
+22
+47
+24
+32
+21
+23
+-1
+23
+-1
+-1
+-1
+-1
+-1
+45
+-1
+-1
+33
+-1
+21
+-1
+-1
+-1
+29
+-1
+52
+23
+-1
+24
+-1
+26
+31
+-1
+-1
+36
+38
+24
+-1
+23
+72
+-1
+38
+-1
+14
+51
+20
+-1
+32
+-1
+18
+-1
+14
+-1
+-1
+-1
+-1
+21
+-1
+25
+-1
+21
+27
+14
+26
+20
+-1
+24
+-1
+15
+-1
+-1
+-1
+15
+-1
+26
+-1
+21
+-1
+-1
+31
+19
+-1
+-1
+21
+22
+-1
+-1
+-1
+-1
+28
+21
+26
+23
+-1
+-1
+22
+-1
+30
+28
+-1
+-1
+41
+34
+41
+-1
+17
+26
+16
+16
+24
+27
+48
+15
+-1
+-1
+-1
+-1
+18
+-1
+17
+22
+-1
+-1
+28
+-1
+33
+-1
+-1
+61
+83
+-1
+50
+-1
+46
+-1
+24
+-1
+25
+22
+-1
+87
+-1
+-1
+-1
+18
+-1
+25
+21
+23
+27
+-1
+36
+66
+17
+-1
+83
+-1
+-1
+-1
+22
+-1
+-1
+70
+-1
+32
+18
+-1
+37
+35
+18
+22
+17
+-1
+-1
+40
+37
+-1
+-1
+22
+15
+-1
+-1
+15
+26
+-1
+44
+23
+24
+30
+-1
+25
+48
+-1
+-1
+-1
+-1
+47
+-1
+24
+-1
+15
+-1
+19
+27
+-1
+-1
+39
+22
+32
+-1
+-1
+23
+21
+-1
+41
+32
+-1
+24
+-1
+-1
+21
+48
+-1
+-1
+-1
+45
+17
+31
+-1
+44
+-1
+-1
+-1
+26
+23
+26
+31
+-1
+-1
+-1
+27
+-1
+31
+-1
+-1
+-1
+-1
+42
+-1
+-1
+27
+-1
+-1
+23
+-1
+-1
+27
+-1
+19
+18
+-1
+29
+-1
+-1
+40
+93
+59
+28
+47
+42
+18
+-1
+-1
+-1
+22
+-1
+32
+20
+-1
+44
+17
+17
+-1
+-1
+-1
+-1
+-1
+-1
+33
+-1
+-1
+29
+-1
+-1
+-1
+25
+25
+28
+-1
+71
+51
+14
+-1
+-1
+-1
+-1
+-1
+-1
+34
+22
+36
+34
+-1
+-1
+-1
+21
+23
+20
+16
+-1
+-1
+-1
+25
+-1
+-1
+24
+28
+-1
+-1
+-1
+17
+-1
+-1
+66
+-1
+16
+19
+-1
+24
+15
+46
+21
+16
+-1
+-1
+-1
+-1
+-1
+-1
+14
+15
+15
+-1
+-1
+-1
+-1
+14
+30
+-1
+-1
+-1
+-1
+86
+26
+35
+29
+29
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+14
+-1
+-1
+21
+-1
+32
+-1
+-1
+14
+-1
+43
+-1
+-1
+52
+26
+22
+-1
+-1
+34
+30
+54
+-1
+-1
+-1
+22
+-1
+-1
+-1
+-1
+17
+24
+15
+-1
+18
+23
+61
+26
+20
+-1
+20
+71
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+21
+-1
+18
+30
+-1
+-1
+24
+26
+42
+-1
+-1
+27
+24
+-1
+27
+-1
+-1
+24
+40
+77
+28
+-1
+18
+-1
+-1
+-1
+22
+-1
+-1
+26
+24
+-1
+25
+-1
+38
+-1
+-1
+16
+-1
+-1
+24
+-1
+-1
+-1
+-1
+-1
+41
+-1
+-1
+-1
+19
+19
+-1
+-1
+-1
+-1
+28
+-1
+-1
+27
+-1
+-1
+35
+36
+35
+-1
+-1
+17
+-1
+-1
+-1
+16
+-1
+-1
+73
+26
+-1
+-1
+20
+42
+-1
+-1
+17
+-1
+51
+34
+27
+-1
+-1
+-1
+21
+37
+-1
+-1
+20
+25
+54
+25
+14
+26
+47
+-1
+19
+32
+25
+-1
+26
+-1
+37
+54
+-1
+-1
+25
+34
+23
+-1
+22
+29
+-1
+-1
+34
+-1
+53
+24
+30
+29
+23
+21
+-1
+49
+-1
+-1
+-1
+20
+-1
+-1
+-1
+57
+33
+49
+19
+20
+23
+31
+26
+-1
+20
+-1
+-1
+-1
+22
+31
+28
+-1
+-1
+-1
+-1
+26
+-1
+-1
+40
+22
+39
+-1
+86
+-1
+-1
+-1
+-1
+-1
+20
+-1
+28
+22
+-1
+33
+27
+31
+-1
+21
+-1
+23
+-1
+22
+-1
+36
+22
+33
+-1
+31
+-1
+16
+32
+-1
+-1
+-1
+23
+-1
+26
+-1
+-1
+-1
+-1
+26
+-1
+49
+-1
+22
+-1
+20
+-1
+16
+-1
+29
+24
+-1
+34
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..30b824a
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+18
+17
+28
+-1
+24
+-1
+-1
+-1
+28
+-1
+33
+-1
+-1
+31
+-1
+-1
+30
+24
+32
+17
+14
+-1
+24
+-1
+31
+21
+29
+-1
+-1
+14
+39
+-1
+-1
+-1
+-1
+-1
+20
+32
+-1
+23
+25
+-1
+-1
+-1
+-1
+25
+-1
+-1
+23
+26
+-1
+-1
+20
+32
+22
+22
+-1
+-1
+48
+-1
+21
+34
+-1
+25
+-1
+-1
+-1
+23
+-1
+36
+33
+23
+-1
+20
+15
+30
+-1
+-1
+31
+-1
+-1
+-1
+-1
+-1
+-1
+15
+21
+21
+-1
+57
+20
+-1
+-1
+-1
+58
+-1
+34
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k9.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k9.txt
new file mode 100644
index 0000000..4e77b5d
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_2x2_k9.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+56
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+46
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+27
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+48
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+29
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+70
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+40
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+27
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+45
+-1
+-1
+-1
+-1
+-1
+34
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+41
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+31
+-1
+-1
+-1
+-1
+-1
+53
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+24
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+42
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+41
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+54
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+20
+-1
+-1
+41
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+40
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+45
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+40
+-1
+-1
+22
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+29
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+24
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+25
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_3x3_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_3x3_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..3d80f4a
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_3x3_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+16
+34
+34
+59
+62
+25
+94
+75
+27
+-1
+30
+100
+-1
+50
+60
+73
+76
+-1
+-1
+29
+88
+-1
+84
+65
+37
+-1
+63
+24
+56
+80
+74
+-1
+29
+64
+-1
+47
+-1
+24
+16
+64
+-1
+-1
+-1
+39
+55
+-1
+60
+31
+79
+86
+-1
+85
+60
+58
+68
+71
+-1
+52
+15
+63
+46
+-1
+-1
+-1
+58
+-1
+-1
+47
+-1
+-1
+48
+-1
+-1
+-1
+57
+94
+-1
+100
+-1
+41
+67
+-1
+-1
+66
+34
+-1
+36
+-1
+20
+48
+-1
+26
+-1
+58
+83
+91
+70
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_4x4_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_4x4_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..3359bf2
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_4x4_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+27
+44
+43
+49
+60
+-1
+-1
+-1
+65
+-1
+-1
+-1
+54
+-1
+23
+51
+40
+69
+49
+69
+-1
+-1
+83
+36
+-1
+52
+-1
+-1
+-1
+75
+46
+-1
+-1
+68
+58
+-1
+53
+-1
+-1
+-1
+66
+77
+27
+-1
+95
+-1
+71
+37
+-1
+-1
+-1
+-1
+23
+-1
+-1
+82
+-1
+37
+-1
+70
+20
+33
+-1
+-1
+64
+-1
+34
+29
+66
+47
+-1
+-1
+80
+-1
+-1
+-1
+16
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+50
+96
+-1
+40
+55
+61
+-1
+-1
+82
+92
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k10.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k10.txt
new file mode 100644
index 0000000..8e94a7a
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k10.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+39
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+77
+-1
+97
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+97
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+88
+89
+-1
+-1
+81
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+66
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+68
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+88
+-1
+-1
+-1
+97
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+76
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+87
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+68
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+78
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+87
+-1
+-1
+-1
+-1
+-1
+-1
+71
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+81
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+99
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+71
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+76
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+65
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k11.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k11.txt
new file mode 100644
index 0000000..03f3f2a
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k11.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+98
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k12.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k12.txt
new file mode 100644
index 0000000..033cb5b
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k12.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k13.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k13.txt
new file mode 100644
index 0000000..033cb5b
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k13.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k5.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k5.txt
new file mode 100644
index 0000000..67ddc56
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k5.txt
@@ -0,0 +1,1000 @@
+7
+11
+4
+11
+13
+5
+3
+22
+18
+30
+3
+3
+3
+3
+3
+3
+15
+33
+16
+18
+3
+15
+7
+3
+74
+4
+8
+-1
+37
+37
+16
+10
+41
+36
+3
+3
+6
+12
+8
+47
+5
+4
+3
+72
+8
+3
+6
+3
+37
+16
+3
+19
+15
+19
+8
+3
+28
+22
+10
+37
+5
+27
+12
+5
+3
+3
+3
+3
+3
+18
+17
+32
+3
+3
+3
+9
+14
+3
+5
+19
+3
+14
+29
+9
+-1
+16
+6
+3
+92
+11
+27
+36
+9
+3
+5
+4
+3
+15
+12
+12
+3
+-1
+3
+20
+10
+5
+22
+19
+3
+16
+25
+6
+54
+3
+10
+3
+4
+3
+4
+3
+6
+3
+3
+21
+31
+21
+18
+6
+69
+11
+3
+3
+78
+9
+63
+12
+14
+4
+4
+6
+6
+3
+-1
+16
+9
+16
+3
+3
+3
+3
+21
+3
+4
+8
+3
+11
+3
+95
+3
+3
+6
+4
+9
+-1
+3
+3
+3
+4
+10
+27
+4
+3
+8
+21
+3
+3
+9
+5
+2
+8
+3
+3
+12
+3
+32
+22
+18
+3
+13
+3
+5
+10
+4
+5
+3
+16
+14
+17
+14
+3
+11
+21
+12
+77
+8
+8
+19
+15
+11
+12
+3
+3
+4
+12
+12
+44
+60
+5
+12
+12
+17
+3
+3
+3
+56
+3
+3
+31
+45
+19
+3
+12
+32
+11
+3
+39
+5
+10
+11
+7
+3
+16
+3
+3
+9
+3
+3
+3
+6
+16
+6
+8
+43
+6
+3
+15
+3
+3
+66
+4
+16
+41
+18
+7
+16
+3
+9
+3
+3
+12
+66
+13
+2
+3
+3
+23
+24
+26
+50
+10
+18
+19
+29
+6
+11
+3
+20
+5
+21
+10
+7
+5
+3
+-1
+2
+-1
+7
+20
+3
+3
+3
+6
+22
+3
+4
+3
+14
+32
+3
+11
+4
+3
+12
+35
+10
+11
+3
+28
+8
+4
+3
+18
+6
+12
+11
+24
+3
+25
+3
+24
+3
+3
+19
+9
+15
+5
+39
+3
+3
+3
+12
+4
+3
+3
+5
+3
+26
+11
+15
+25
+3
+15
+2
+3
+10
+5
+71
+55
+25
+8
+4
+6
+26
+18
+41
+3
+3
+97
+3
+26
+13
+3
+13
+3
+15
+10
+43
+18
+6
+3
+31
+9
+19
+17
+21
+3
+20
+22
+3
+39
+21
+7
+14
+3
+30
+16
+9
+24
+16
+49
+16
+27
+4
+3
+3
+2
+9
+3
+3
+13
+12
+5
+6
+11
+6
+41
+17
+25
+21
+3
+10
+3
+5
+29
+39
+12
+3
+44
+16
+13
+3
+2
+3
+88
+-1
+8
+22
+5
+15
+84
+18
+19
+6
+3
+3
+21
+3
+80
+13
+4
+6
+3
+28
+3
+36
+11
+13
+3
+3
+8
+7
+15
+14
+3
+58
+20
+5
+11
+25
+3
+3
+13
+14
+10
+5
+5
+6
+3
+3
+11
+3
+3
+8
+33
+4
+18
+11
+16
+14
+3
+3
+10
+3
+3
+30
+69
+35
+3
+25
+13
+3
+15
+13
+5
+3
+3
+3
+37
+-1
+16
+14
+55
+3
+3
+5
+21
+15
+34
+3
+3
+3
+3
+5
+65
+-1
+3
+22
+48
+22
+4
+13
+18
+9
+19
+97
+3
+5
+3
+3
+11
+7
+4
+3
+18
+8
+48
+20
+6
+23
+15
+10
+24
+25
+10
+70
+16
+9
+9
+3
+3
+49
+3
+8
+3
+68
+3
+14
+3
+3
+5
+3
+3
+3
+27
+13
+3
+3
+4
+17
+3
+3
+4
+32
+3
+21
+3
+17
+20
+10
+37
+23
+3
+3
+5
+3
+3
+3
+11
+4
+12
+3
+12
+62
+9
+20
+34
+3
+6
+20
+15
+3
+30
+3
+21
+17
+9
+21
+18
+17
+13
+20
+3
+34
+9
+3
+16
+18
+16
+12
+3
+3
+56
+41
+11
+3
+12
+24
+27
+13
+5
+57
+8
+5
+70
+9
+12
+23
+5
+3
+9
+10
+14
+24
+17
+3
+4
+8
+4
+3
+21
+35
+3
+19
+5
+36
+3
+3
+25
+70
+3
+3
+23
+71
+26
+3
+16
+57
+3
+16
+11
+4
+3
+12
+16
+3
+26
+3
+38
+31
+17
+3
+2
+40
+3
+43
+26
+3
+9
+4
+39
+8
+19
+3
+3
+15
+5
+8
+3
+5
+3
+23
+3
+59
+12
+10
+3
+3
+10
+12
+16
+3
+16
+6
+3
+3
+3
+6
+3
+3
+13
+13
+11
+14
+62
+3
+28
+51
+3
+13
+21
+3
+13
+3
+10
+12
+3
+11
+3
+27
+5
+9
+3
+19
+3
+26
+23
+6
+3
+13
+2
+11
+3
+4
+44
+7
+17
+12
+3
+12
+2
+33
+8
+11
+32
+36
+22
+6
+11
+3
+5
+13
+3
+3
+14
+15
+10
+3
+3
+16
+3
+3
+61
+11
+3
+14
+9
+9
+3
+7
+3
+7
+8
+11
+11
+39
+100
+-1
+14
+30
+6
+48
+64
+3
+3
+17
+5
+15
+3
+11
+3
+3
+12
+11
+3
+38
+3
+3
+35
+8
+-1
+31
+3
+3
+11
+35
+10
+3
+3
+3
+9
+3
+18
+59
+6
+17
+6
+3
+-1
+11
+9
+22
+-1
+73
+20
+39
+49
+15
+4
+19
+63
+21
+35
+3
+6
+10
+3
+3
+8
+3
+10
+18
+-1
+24
+4
+4
+3
+15
+49
+14
+3
+3
+57
+3
+6
+3
+3
+4
+6
+33
+47
+44
+3
+8
+21
+4
+3
+3
+45
+6
+30
+3
+8
+3
+13
+20
+4
+57
+3
+5
+3
+10
+3
+-1
+21
+3
+5
+-1
+5
+31
+3
+7
+14
+3
+3
+32
+8
+33
+49
+15
+3
+3
+3
+3
+10
+87
+17
+3
+7
+10
+4
+3
+47
+23
+3
+4
+3
+12
+18
+6
+3
+5
+3
+-1
+3
+65
+3
+29
+3
+3
+3
+3
+3
+22
+37
+20
+18
+7
+15
+-1
+5
+21
+3
+17
+3
+7
+2
+21
+28
+16
+6
+8
+28
+3
+5
+4
+5
+3
+3
+9
+3
+11
+13
+9
+61
+39
+10
+15
+66
+14
+54
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k6.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k6.txt
new file mode 100644
index 0000000..28b9936
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k6.txt
@@ -0,0 +1,1000 @@
+6
+10
+17
+13
+16
+6
+25
+12
+8
+22
+10
+8
+24
+8
+7
+10
+48
+9
+17
+8
+52
+32
+57
+9
+22
+75
+71
+15
+13
+15
+84
+25
+9
+8
+12
+38
+41
+84
+16
+17
+52
+9
+53
+82
+33
+30
+9
+61
+31
+-1
+24
+48
+9
+31
+9
+10
+73
+58
+-1
+38
+8
+7
+53
+26
+8
+27
+9
+-1
+74
+33
+9
+8
+-1
+-1
+13
+9
+90
+12
+13
+40
+12
+39
+21
+9
+9
+67
+11
+22
+20
+23
+27
+9
+12
+35
+68
+45
+11
+18
+28
+34
+23
+11
+49
+50
+21
+15
+8
+35
+77
+17
+13
+9
+25
+8
+21
+11
+-1
+8
+8
+10
+-1
+12
+9
+12
+10
+23
+18
+10
+36
+57
+-1
+23
+24
+42
+70
+23
+11
+37
+15
+-1
+-1
+25
+11
+10
+12
+53
+9
+11
+39
+45
+-1
+9
+12
+47
+24
+26
+25
+20
+30
+40
+12
+8
+39
+-1
+9
+36
+-1
+15
+24
+40
+8
+69
+13
+12
+10
+11
+13
+17
+-1
+38
+73
+32
+-1
+9
+-1
+13
+55
+39
+9
+14
+12
+45
+13
+18
+11
+10
+31
+10
+14
+24
+9
+12
+-1
+-1
+9
+31
+34
+46
+27
+43
+22
+9
+26
+8
+-1
+17
+26
+56
+39
+11
+-1
+60
+42
+18
+17
+7
+78
+38
+22
+8
+59
+13
+12
+42
+13
+42
+13
+69
+-1
+55
+7
+37
+-1
+-1
+41
+8
+10
+33
+46
+-1
+56
+12
+8
+20
+9
+39
+29
+-1
+18
+42
+37
+17
+13
+27
+9
+30
+34
+25
+86
+13
+10
+9
+29
+13
+10
+20
+12
+62
+38
+9
+19
+9
+19
+22
+25
+22
+12
+8
+9
+-1
+67
+12
+10
+24
+13
+54
+20
+23
+-1
+20
+71
+37
+30
+11
+11
+52
+10
+99
+10
+8
+19
+11
+10
+24
+50
+14
+-1
+19
+49
+24
+9
+14
+15
+50
+7
+30
+15
+9
+18
+8
+15
+21
+41
+18
+47
+65
+57
+21
+12
+14
+79
+13
+50
+10
+10
+14
+28
+22
+13
+18
+9
+7
+30
+31
+16
+-1
+63
+34
+81
+18
+8
+9
+70
+9
+34
+64
+56
+14
+-1
+13
+94
+-1
+-1
+9
+33
+7
+25
+52
+26
+35
+15
+38
+38
+11
+41
+84
+55
+65
+14
+8
+12
+38
+9
+17
+78
+11
+11
+-1
+24
+16
+18
+58
+10
+60
+69
+73
+9
+33
+16
+73
+23
+30
+14
+17
+11
+19
+11
+13
+11
+20
+58
+11
+83
+28
+19
+19
+28
+-1
+-1
+13
+60
+25
+17
+58
+45
+-1
+-1
+46
+43
+9
+23
+8
+31
+36
+27
+-1
+30
+7
+70
+8
+10
+20
+15
+31
+11
+68
+-1
+19
+9
+17
+59
+41
+12
+11
+10
+17
+36
+11
+10
+16
+8
+22
+33
+74
+46
+-1
+17
+-1
+15
+43
+17
+48
+27
+14
+14
+8
+9
+12
+37
+-1
+11
+-1
+57
+40
+27
+58
+12
+22
+16
+47
+9
+29
+28
+32
+9
+9
+10
+32
+11
+-1
+46
+67
+80
+22
+26
+8
+98
+7
+71
+9
+24
+24
+30
+76
+49
+9
+55
+9
+29
+-1
+11
+25
+-1
+65
+13
+33
+17
+11
+37
+46
+21
+83
+11
+27
+81
+22
+16
+14
+45
+78
+18
+16
+22
+32
+10
+-1
+40
+8
+23
+70
+34
+13
+59
+21
+-1
+25
+63
+48
+12
+61
+18
+-1
+91
+9
+66
+20
+9
+-1
+10
+8
+40
+94
+7
+32
+42
+-1
+9
+12
+56
+15
+9
+24
+-1
+10
+63
+47
+28
+-1
+27
+12
+-1
+-1
+10
+20
+20
+65
+11
+-1
+-1
+-1
+19
+14
+16
+12
+-1
+20
+12
+38
+11
+14
+66
+12
+96
+7
+11
+-1
+50
+19
+37
+22
+8
+13
+26
+21
+11
+14
+9
+-1
+11
+-1
+10
+28
+43
+9
+9
+22
+12
+-1
+-1
+63
+10
+8
+22
+39
+9
+14
+18
+25
+63
+42
+11
+38
+13
+56
+37
+22
+10
+19
+32
+11
+12
+91
+8
+71
+42
+15
+19
+20
+52
+-1
+10
+10
+14
+9
+9
+-1
+10
+48
+-1
+19
+75
+25
+46
+9
+40
+18
+18
+13
+44
+51
+11
+25
+12
+51
+10
+36
+29
+12
+-1
+13
+23
+22
+-1
+-1
+22
+12
+54
+10
+10
+9
+28
+49
+36
+14
+9
+9
+44
+8
+53
+31
+20
+15
+33
+15
+77
+66
+21
+27
+11
+46
+17
+-1
+-1
+76
+15
+25
+13
+18
+9
+8
+31
+14
+46
+15
+41
+16
+35
+-1
+19
+16
+14
+9
+23
+12
+25
+12
+35
+26
+14
+76
+11
+9
+63
+17
+13
+19
+19
+7
+11
+31
+27
+52
+9
+31
+27
+16
+11
+57
+11
+51
+35
+12
+13
+18
+-1
+16
+9
+16
+37
+8
+52
+11
+40
+19
+10
+28
+10
+84
+18
+8
+27
+94
+38
+-1
+26
+-1
+26
+12
+22
+59
+-1
+-1
+9
+77
+24
+36
+7
+42
+9
+29
+23
+17
+28
+15
+19
+-1
+52
+10
+20
+10
+11
+53
+-1
+10
+11
+24
+8
+8
+8
+25
+22
+25
+12
+13
+85
+15
+11
+66
+12
+36
+64
+31
+8
+67
+29
+80
+10
+8
+28
+10
+41
+14
+21
+64
+14
+59
+8
+59
+-1
+35
+7
+8
+17
+12
+22
+13
+17
+12
+17
+57
+25
+53
+7
+16
+18
+98
+61
+8
+12
+20
+46
+11
+23
+11
+30
+20
+-1
+34
+13
+-1
+10
+10
+15
+10
+33
+19
+8
+70
+23
+45
+68
+9
+15
+-1
+20
+31
+8
+30
+18
+37
+17
+9
+24
+9
+12
+34
+19
+19
+12
+-1
+46
+13
+10
+14
+10
+52
+-1
+10
+67
+8
+40
+72
+49
+-1
+41
+17
+42
+-1
+25
+-1
+50
+37
+9
+44
+28
+17
+24
+29
+12
+66
+60
+29
+10
+17
+10
+25
+18
+9
+70
+-1
+53
+14
+16
+8
+9
+26
+22
+21
+55
+9
+16
+-1
+21
+18
+-1
+37
+-1
+58
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k7.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k7.txt
new file mode 100644
index 0000000..69c29ee
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k7.txt
@@ -0,0 +1,1000 @@
+13
+19
+19
+22
+26
+13
+37
+43
+28
+43
+27
+72
+-1
+86
+-1
+-1
+-1
+-1
+85
+31
+73
+37
+31
+56
+-1
+-1
+-1
+16
+66
+88
+-1
+16
+-1
+22
+20
+-1
+98
+-1
+26
+63
+17
+-1
+49
+-1
+-1
+13
+-1
+17
+62
+16
+50
+23
+27
+28
+60
+26
+-1
+27
+70
+12
+23
+-1
+19
+55
+29
+21
+87
+45
+13
+14
+-1
+-1
+44
+34
+76
+25
+47
+-1
+36
+66
+24
+-1
+69
+-1
+19
+92
+32
+17
+-1
+10
+-1
+13
+15
+17
+-1
+27
+20
+-1
+24
+87
+37
+47
+-1
+-1
+25
+18
+20
+-1
+80
+64
+45
+28
+55
+27
+-1
+-1
+16
+-1
+43
+32
+19
+46
+-1
+52
+22
+19
+65
+47
+-1
+-1
+24
+-1
+13
+11
+44
+32
+11
+39
+28
+25
+42
+9
+-1
+46
+78
+-1
+-1
+38
+-1
+-1
+18
+29
+59
+51
+31
+18
+83
+13
+94
+11
+79
+43
+12
+22
+42
+42
+-1
+-1
+-1
+22
+-1
+-1
+24
+-1
+36
+16
+65
+29
+31
+-1
+21
+-1
+15
+27
+22
+57
+44
+-1
+-1
+45
+21
+-1
+-1
+30
+-1
+87
+14
+-1
+-1
+44
+76
+38
+-1
+-1
+73
+63
+22
+13
+-1
+-1
+31
+19
+37
+33
+12
+18
+14
+86
+12
+-1
+-1
+38
+-1
+-1
+51
+92
+11
+39
+52
+47
+33
+23
+59
+68
+24
+48
+-1
+-1
+21
+-1
+-1
+47
+37
+22
+-1
+58
+-1
+19
+26
+41
+93
+71
+-1
+-1
+17
+11
+28
+-1
+26
+16
+-1
+16
+29
+-1
+72
+32
+33
+86
+27
+36
+-1
+-1
+-1
+-1
+15
+39
+-1
+14
+55
+12
+-1
+36
+32
+-1
+32
+-1
+-1
+24
+17
+53
+26
+95
+23
+24
+66
+79
+-1
+94
+33
+-1
+31
+26
+36
+-1
+89
+17
+12
+58
+53
+24
+-1
+18
+26
+-1
+54
+34
+10
+24
+-1
+17
+52
+58
+19
+18
+86
+95
+-1
+-1
+70
+59
+-1
+22
+93
+26
+34
+-1
+55
+-1
+24
+19
+33
+-1
+30
+-1
+-1
+17
+-1
+78
+-1
+-1
+61
+75
+28
+22
+-1
+-1
+19
+12
+27
+80
+22
+11
+-1
+71
+22
+-1
+-1
+55
+-1
+14
+17
+-1
+13
+92
+39
+-1
+37
+72
+84
+-1
+38
+15
+47
+-1
+-1
+18
+24
+-1
+86
+82
+84
+-1
+-1
+-1
+65
+66
+-1
+22
+15
+13
+64
+-1
+61
+-1
+12
+28
+73
+12
+-1
+21
+53
+52
+-1
+22
+44
+17
+23
+13
+63
+27
+45
+66
+81
+-1
+-1
+38
+-1
+-1
+-1
+-1
+50
+9
+23
+36
+43
+-1
+-1
+-1
+-1
+14
+14
+21
+-1
+-1
+-1
+37
+44
+20
+-1
+61
+45
+-1
+10
+-1
+41
+30
+-1
+-1
+16
+40
+62
+16
+15
+29
+-1
+-1
+37
+25
+29
+29
+39
+22
+-1
+27
+95
+87
+44
+-1
+-1
+-1
+-1
+64
+44
+97
+33
+58
+34
+51
+36
+-1
+15
+16
+21
+18
+82
+-1
+57
+40
+36
+-1
+55
+45
+52
+-1
+-1
+-1
+18
+-1
+-1
+69
+14
+-1
+-1
+-1
+36
+25
+27
+45
+33
+-1
+97
+55
+22
+32
+-1
+-1
+58
+-1
+59
+45
+69
+13
+40
+21
+-1
+-1
+40
+24
+-1
+26
+72
+96
+-1
+-1
+16
+-1
+-1
+57
+21
+-1
+-1
+90
+23
+-1
+31
+13
+34
+63
+39
+29
+-1
+71
+27
+37
+41
+51
+36
+23
+24
+23
+13
+22
+-1
+37
+-1
+18
+75
+17
+-1
+67
+46
+-1
+66
+15
+19
+-1
+13
+32
+15
+-1
+38
+-1
+84
+11
+-1
+93
+24
+11
+-1
+35
+-1
+-1
+-1
+30
+19
+12
+38
+-1
+-1
+-1
+26
+9
+19
+64
+33
+19
+22
+38
+-1
+62
+71
+82
+41
+31
+49
+-1
+48
+43
+46
+28
+-1
+65
+-1
+-1
+84
+-1
+44
+71
+-1
+51
+-1
+10
+32
+-1
+27
+11
+-1
+-1
+-1
+27
+75
+-1
+11
+18
+16
+26
+14
+-1
+10
+36
+-1
+68
+-1
+24
+15
+25
+15
+25
+31
+50
+-1
+-1
+-1
+-1
+29
+51
+-1
+94
+-1
+57
+-1
+55
+-1
+14
+-1
+-1
+60
+-1
+90
+15
+-1
+30
+98
+41
+34
+-1
+49
+-1
+21
+-1
+24
+-1
+19
+17
+10
+23
+-1
+-1
+73
+-1
+30
+96
+90
+50
+33
+90
+43
+-1
+-1
+-1
+11
+-1
+15
+60
+44
+12
+-1
+-1
+13
+32
+-1
+26
+24
+-1
+15
+19
+73
+17
+-1
+55
+-1
+73
+-1
+19
+-1
+-1
+62
+-1
+62
+12
+38
+69
+-1
+48
+42
+70
+77
+-1
+73
+77
+79
+47
+-1
+-1
+94
+-1
+82
+19
+25
+21
+31
+11
+43
+71
+24
+26
+-1
+12
+-1
+71
+-1
+11
+18
+26
+18
+-1
+58
+13
+14
+13
+23
+18
+-1
+-1
+20
+-1
+36
+16
+11
+44
+62
+-1
+34
+12
+-1
+47
+68
+14
+60
+20
+-1
+29
+28
+16
+50
+39
+-1
+19
+34
+-1
+19
+59
+38
+-1
+18
+13
+-1
+-1
+43
+49
+29
+-1
+27
+13
+-1
+35
+30
+11
+57
+51
+-1
+21
+31
+38
+-1
+17
+20
+33
+96
+74
+52
+18
+21
+82
+-1
+19
+-1
+39
+-1
+11
+28
+-1
+-1
+-1
+16
+-1
+52
+-1
+20
+34
+56
+52
+18
+28
+33
+13
+56
+-1
+11
+-1
+10
+27
+21
+21
+-1
+49
+-1
+25
+20
+28
+84
+71
+86
+-1
+-1
+46
+10
+-1
+-1
+25
+29
+19
+49
+-1
+-1
+32
+-1
+-1
+33
+20
+55
+15
+-1
+67
+99
+65
+-1
+-1
+85
+19
+10
+30
+61
+-1
+61
+20
+82
+11
+-1
+-1
+-1
+-1
+-1
+53
+72
+-1
+-1
+28
+-1
+78
+27
+68
+49
+-1
+82
+57
+59
+17
+11
+-1
+-1
+57
+45
+53
+11
+19
+50
+99
+-1
+26
+81
+16
+52
+-1
+25
+-1
+12
+-1
+-1
+43
+28
+41
+46
+93
+39
+60
+73
+-1
+-1
+75
+-1
+29
+27
+54
+28
+39
+-1
+23
+28
+73
+-1
+-1
+39
+13
+-1
+77
+91
+100
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8.txt
new file mode 100644
index 0000000..06a1bc4
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8.txt
@@ -0,0 +1,1000 @@
+15
+45
+71
+-1
+16
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+87
+-1
+-1
+-1
+-1
+89
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+82
+-1
+26
+-1
+25
+20
+-1
+79
+-1
+15
+61
+42
+81
+56
+-1
+20
+-1
+42
+-1
+46
+27
+60
+-1
+69
+-1
+79
+22
+-1
+-1
+-1
+-1
+89
+41
+40
+22
+99
+-1
+-1
+82
+-1
+-1
+-1
+74
+-1
+-1
+-1
+52
+52
+52
+-1
+-1
+29
+37
+89
+-1
+87
+-1
+-1
+-1
+-1
+17
+29
+-1
+87
+-1
+21
+-1
+36
+52
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+95
+62
+72
+51
+-1
+-1
+80
+-1
+-1
+-1
+14
+-1
+-1
+31
+-1
+40
+-1
+96
+-1
+-1
+83
+26
+-1
+-1
+84
+-1
+60
+-1
+85
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+21
+43
+-1
+-1
+61
+59
+96
+39
+-1
+43
+28
+-1
+-1
+-1
+31
+-1
+-1
+68
+61
+83
+-1
+-1
+44
+-1
+16
+-1
+-1
+-1
+-1
+45
+-1
+-1
+94
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+94
+57
+-1
+-1
+14
+-1
+-1
+44
+-1
+-1
+-1
+24
+28
+-1
+40
+-1
+-1
+84
+-1
+-1
+-1
+96
+34
+51
+-1
+65
+-1
+26
+49
+-1
+-1
+-1
+51
+-1
+-1
+-1
+-1
+-1
+-1
+99
+-1
+-1
+-1
+38
+30
+-1
+-1
+-1
+-1
+85
+60
+35
+-1
+-1
+-1
+-1
+32
+-1
+-1
+-1
+35
+-1
+49
+57
+-1
+67
+-1
+64
+-1
+-1
+-1
+-1
+-1
+63
+56
+63
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+34
+91
+97
+-1
+-1
+-1
+-1
+34
+60
+-1
+35
+-1
+59
+-1
+-1
+-1
+-1
+-1
+-1
+74
+-1
+-1
+-1
+49
+28
+44
+-1
+20
+-1
+88
+-1
+17
+36
+75
+-1
+-1
+70
+-1
+-1
+-1
+74
+-1
+48
+-1
+-1
+-1
+-1
+15
+-1
+24
+-1
+-1
+48
+43
+64
+74
+-1
+-1
+93
+-1
+-1
+-1
+64
+60
+28
+28
+39
+48
+-1
+-1
+-1
+37
+-1
+94
+52
+52
+-1
+-1
+-1
+-1
+61
+25
+79
+-1
+-1
+97
+-1
+-1
+-1
+41
+-1
+56
+-1
+88
+-1
+-1
+81
+76
+-1
+-1
+64
+94
+-1
+18
+-1
+-1
+-1
+64
+44
+95
+-1
+75
+85
+37
+79
+-1
+-1
+93
+62
+-1
+-1
+-1
+-1
+-1
+-1
+71
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+39
+43
+-1
+67
+46
+-1
+34
+14
+-1
+87
+-1
+-1
+92
+-1
+-1
+-1
+67
+-1
+-1
+63
+-1
+-1
+-1
+71
+20
+49
+-1
+-1
+53
+78
+16
+-1
+27
+92
+-1
+-1
+-1
+-1
+62
+66
+-1
+49
+18
+-1
+44
+92
+-1
+41
+-1
+-1
+-1
+23
+-1
+30
+77
+-1
+23
+49
+-1
+-1
+14
+-1
+-1
+-1
+23
+-1
+-1
+97
+36
+68
+-1
+71
+-1
+49
+-1
+-1
+-1
+-1
+-1
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+70
+-1
+88
+49
+-1
+-1
+92
+78
+55
+28
+77
+47
+-1
+44
+-1
+61
+-1
+83
+79
+-1
+-1
+-1
+-1
+48
+-1
+36
+77
+91
+-1
+-1
+28
+-1
+-1
+57
+-1
+35
+-1
+44
+65
+91
+42
+28
+51
+-1
+-1
+83
+80
+44
+32
+-1
+-1
+-1
+92
+52
+49
+-1
+-1
+19
+-1
+-1
+52
+59
+-1
+79
+-1
+-1
+-1
+-1
+90
+-1
+53
+18
+-1
+21
+-1
+-1
+49
+100
+-1
+-1
+-1
+-1
+96
+48
+-1
+95
+-1
+-1
+-1
+39
+-1
+89
+-1
+21
+73
+-1
+14
+29
+-1
+36
+-1
+-1
+-1
+15
+-1
+-1
+61
+27
+-1
+85
+-1
+-1
+-1
+36
+59
+-1
+94
+23
+31
+34
+-1
+-1
+-1
+-1
+-1
+96
+-1
+-1
+66
+37
+40
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+18
+-1
+-1
+100
+36
+-1
+-1
+-1
+-1
+43
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+97
+42
+25
+-1
+16
+-1
+-1
+-1
+-1
+59
+-1
+-1
+-1
+-1
+-1
+15
+48
+-1
+56
+22
+-1
+87
+-1
+-1
+-1
+-1
+29
+-1
+-1
+-1
+63
+-1
+-1
+-1
+43
+-1
+64
+51
+-1
+100
+-1
+60
+-1
+33
+65
+52
+-1
+-1
+62
+62
+-1
+21
+-1
+58
+41
+41
+-1
+-1
+43
+-1
+48
+68
+97
+49
+-1
+40
+-1
+-1
+28
+-1
+17
+-1
+-1
+-1
+21
+-1
+-1
+-1
+-1
+-1
+73
+-1
+80
+-1
+-1
+31
+-1
+43
+65
+57
+-1
+29
+30
+39
+79
+-1
+38
+-1
+-1
+-1
+-1
+-1
+80
+69
+-1
+-1
+-1
+67
+68
+75
+74
+37
+60
+80
+76
+-1
+-1
+-1
+59
+-1
+-1
+-1
+90
+-1
+19
+63
+23
+47
+96
+86
+91
+-1
+-1
+29
+32
+-1
+67
+-1
+72
+-1
+-1
+-1
+-1
+84
+-1
+-1
+-1
+56
+80
+67
+75
+93
+-1
+-1
+15
+71
+-1
+41
+-1
+-1
+-1
+-1
+-1
+16
+-1
+-1
+50
+68
+31
+46
+38
+84
+82
+-1
+-1
+77
+79
+99
+-1
+-1
+-1
+68
+-1
+-1
+37
+36
+-1
+93
+-1
+-1
+-1
+53
+-1
+-1
+14
+32
+51
+-1
+-1
+-1
+-1
+-1
+59
+-1
+28
+-1
+-1
+-1
+21
+99
+38
+82
+29
+-1
+-1
+-1
+-1
+26
+88
+28
+92
+60
+99
+-1
+-1
+-1
+53
+-1
+-1
+-1
+85
+-1
+-1
+-1
+40
+35
+28
+-1
+-1
+-1
+-1
+75
+-1
+14
+-1
+-1
+-1
+-1
+-1
+14
+-1
+-1
+-1
+-1
+17
+-1
+-1
+-1
+18
+16
+99
+99
+-1
+-1
+95
+-1
+54
+-1
+38
+-1
+28
+-1
+38
+79
+-1
+23
+41
+-1
+73
+-1
+-1
+-1
+-1
+52
+32
+-1
+27
+-1
+-1
+-1
+-1
+94
+-1
+-1
+37
+-1
+-1
+18
+100
+-1
+29
+-1
+-1
+90
+76
+28
+-1
+88
+-1
+-1
+-1
+-1
+63
+80
+-1
+71
+19
+63
+-1
+53
+-1
+99
+-1
+-1
+-1
+24
+27
+-1
+73
+-1
+-1
+-1
+48
+-1
+-1
+78
+34
+-1
+-1
+18
+-1
+66
+-1
+60
+86
+73
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..961fe50
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+19
+46
+48
+65
+27
+34
+-1
+-1
+-1
+-1
+88
+-1
+69
+-1
+-1
+17
+-1
+-1
+-1
+-1
+62
+26
+-1
+-1
+-1
+-1
+-1
+89
+-1
+-1
+59
+22
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+55
+-1
+-1
+31
+62
+48
+88
+76
+64
+38
+78
+84
+81
+26
+33
+-1
+48
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+42
+-1
+-1
+35
+66
+94
+35
+94
+72
+73
+-1
+44
+33
+-1
+-1
+23
+-1
+27
+-1
+-1
+-1
+-1
+-1
+42
+26
+-1
+58
+89
+21
+95
+-1
+-1
+-1
+85
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k9.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k9.txt
new file mode 100644
index 0000000..0b10358
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_5x5_k9.txt
@@ -0,0 +1,1000 @@
+57
+72
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+80
+-1
+99
+95
+-1
+58
+-1
+-1
+-1
+51
+-1
+-1
+-1
+-1
+-1
+-1
+98
+-1
+-1
+-1
+-1
+-1
+86
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+76
+89
+96
+-1
+91
+-1
+49
+-1
+-1
+68
+78
+63
+-1
+65
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+75
+-1
+-1
+-1
+-1
+40
+-1
+-1
+-1
+-1
+-1
+-1
+79
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+70
+-1
+-1
+-1
+-1
+-1
+64
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+63
+-1
+-1
+-1
+-1
+38
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+62
+-1
+-1
+-1
+-1
+-1
+-1
+67
+82
+-1
+-1
+-1
+-1
+43
+-1
+-1
+95
+-1
+-1
+55
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+62
+-1
+-1
+-1
+-1
+-1
+85
+48
+-1
+-1
+81
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+36
+65
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+67
+-1
+-1
+-1
+86
+-1
+40
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+94
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+72
+-1
+92
+-1
+-1
+-1
+75
+-1
+-1
+-1
+-1
+-1
+36
+-1
+-1
+-1
+-1
+39
+70
+-1
+-1
+-1
+91
+-1
+-1
+-1
+-1
+49
+-1
+-1
+-1
+-1
+87
+99
+-1
+-1
+43
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+77
+-1
+27
+-1
+-1
+-1
+-1
+38
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+54
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+83
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+57
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+57
+-1
+88
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+57
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+81
+93
+41
+-1
+-1
+-1
+-1
+-1
+46
+-1
+-1
+-1
+-1
+-1
+-1
+95
+-1
+-1
+-1
+-1
+-1
+-1
+73
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+95
+-1
+-1
+-1
+-1
+-1
+90
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+48
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+55
+-1
+52
+-1
+100
+-1
+-1
+-1
+-1
+-1
+-1
+35
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+73
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+70
+-1
+53
+-1
+79
+-1
+-1
+71
+-1
+-1
+-1
+-1
+90
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+63
+43
+-1
+53
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+48
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+73
+-1
+-1
+25
+-1
+-1
+29
+-1
+-1
+-1
+-1
+-1
+79
+-1
+-1
+19
+-1
+-1
+95
+-1
+-1
+60
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+90
+-1
+-1
+99
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+66
+-1
+-1
+-1
+-1
+77
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+58
+-1
+-1
+40
+-1
+-1
+-1
+-1
+49
+-1
+-1
+-1
+37
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+79
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+60
+-1
+41
+-1
+-1
+-1
+82
+-1
+-1
+-1
+95
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+34
+58
+-1
+88
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+91
+55
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+54
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+55
+-1
+-1
+42
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+49
+-1
+-1
+87
+-1
+-1
+79
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+88
+-1
+-1
+89
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+46
+-1
+100
+-1
+-1
+-1
+-1
+-1
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+92
+65
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+36
+-1
+-1
+-1
+-1
+-1
+62
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+53
+-1
+-1
+-1
+-1
+85
+-1
+-1
+72
+-1
+-1
+-1
+-1
+-1
+-1
+84
+89
+33
+-1
+-1
+47
+-1
+-1
+-1
+-1
+-1
+52
+-1
+-1
+-1
+-1
+-1
+57
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+75
+44
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+49
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+25
+-1
+-1
+-1
+-1
+-1
+62
+-1
+-1
+-1
+56
+-1
+88
+-1
+-1
+78
+63
+36
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+82
+-1
+-1
+-1
+-1
+37
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_6x6_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_6x6_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..c21764c
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_6x6_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+63
+95
+89
+-1
+75
+-1
+-1
+-1
+-1
+86
+95
+43
+-1
+-1
+-1
+18
+35
+22
+-1
+-1
+54
+66
+41
+-1
+-1
+-1
+-1
+91
+-1
+-1
+-1
+-1
+97
+-1
+-1
+28
+-1
+54
+-1
+-1
+-1
+-1
+38
+-1
+-1
+-1
+-1
+-1
+22
+89
+-1
+-1
+-1
+-1
+-1
+83
+-1
+-1
+-1
+-1
+30
+30
+-1
+-1
+-1
+68
+-1
+-1
+18
+-1
+28
+-1
+-1
+44
+-1
+-1
+-1
+55
+69
+-1
+-1
+-1
+74
+-1
+23
+-1
+-1
+-1
+-1
+-1
+51
+-1
+-1
+-1
+88
+92
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k10.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k10.txt
new file mode 100644
index 0000000..ed3977a
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k10.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+58
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+83
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+74
+-1
+86
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+79
+-1
+-1
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+98
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+84
+-1
+70
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+78
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+74
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+56
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+77
+-1
+-1
+95
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+47
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+72
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+84
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+96
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+45
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+85
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+85
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+98
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+98
+70
+-1
+-1
+-1
+-1
+-1
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..11d884d
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_7x7_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+43
+48
+67
+25
+23
+66
+-1
+37
+-1
+-1
+-1
+41
+-1
+-1
+-1
+-1
+97
+-1
+-1
+-1
+51
+65
+-1
+31
+-1
+-1
+-1
+51
+21
+-1
+-1
+-1
+-1
+85
+30
+79
+-1
+-1
+-1
+62
+-1
+-1
+-1
+-1
+-1
+16
+-1
+25
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+56
+24
+-1
+-1
+33
+-1
+39
+-1
+94
+-1
+19
+89
+-1
+-1
+14
+78
+-1
+-1
+-1
+38
+-1
+15
+-1
+-1
+61
+-1
+36
+-1
+89
+-1
+-1
+14
+51
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_8x8_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_8x8_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..7ac1041
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_8x8_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+43
+54
+14
+57
+88
+-1
+-1
+-1
+-1
+-1
+27
+16
+-1
+66
+87
+37
+76
+-1
+-1
+-1
+37
+72
+53
+34
+88
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+26
+-1
+-1
+99
+-1
+-1
+49
+58
+-1
+-1
+-1
+49
+71
+39
+28
+-1
+-1
+-1
+-1
+-1
+39
+-1
+40
+-1
+-1
+-1
+-1
+27
+-1
+-1
+48
+-1
+49
+30
+35
+-1
+-1
+-1
+-1
+86
+97
+59
+-1
+55
+97
+72
+-1
+-1
+57
+-1
+-1
+16
+-1
+-1
+-1
+-1
+47
+-1
+37
+-1
+-1
+81
+-1
+44
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_9x9_k8_different_grid_sizes.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_9x9_k8_different_grid_sizes.txt
new file mode 100644
index 0000000..69b2249
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_9x9_k8_different_grid_sizes.txt
@@ -0,0 +1,100 @@
+26
+31
+45
+35
+-1
+-1
+-1
+-1
+-1
+-1
+42
+29
+-1
+29
+53
+37
+36
+35
+77
+-1
+-1
+52
+83
+-1
+-1
+-1
+-1
+30
+55
+-1
+64
+-1
+-1
+86
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+93
+39
+-1
+45
+-1
+-1
+-1
+-1
+25
+-1
+-1
+41
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+74
+50
+-1
+-1
+-1
+21
+82
+34
+-1
+32
+-1
+-1
+-1
+31
+-1
+65
+46
+-1
+50
+-1
+37
+-1
+53
+-1
+-1
+73
+-1
+94
+-1
+-1
+-1
+47
+36
+-1
+60
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus.txt
new file mode 100644
index 0000000..763fca9
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus.txt
@@ -0,0 +1,1000 @@
+2
+3
+3
+2
+2
+27
+2
+2
+2
+2
+17
+2
+3
+15
+2
+2
+2
+2
+3
+20
+3
+2
+2
+20
+10
+9
+10
+3
+12
+2
+18
+2
+2
+3
+2
+5
+2
+2
+6
+15
+8
+3
+2
+2
+2
+2
+2
+3
+2
+16
+2
+3
+2
+7
+2
+2
+2
+2
+13
+2
+2
+2
+3
+2
+2
+2
+3
+2
+3
+2
+18
+3
+2
+10
+2
+2
+2
+12
+2
+4
+6
+2
+3
+2
+2
+2
+20
+3
+3
+3
+2
+3
+2
+3
+2
+2
+6
+8
+2
+11
+9
+2
+3
+18
+3
+8
+2
+2
+16
+9
+2
+11
+11
+2
+-1
+2
+2
+9
+2
+2
+16
+2
+2
+9
+2
+2
+4
+2
+2
+2
+3
+2
+2
+15
+2
+10
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+11
+3
+2
+9
+2
+2
+2
+2
+2
+9
+4
+2
+2
+20
+2
+9
+11
+13
+7
+2
+2
+2
+10
+2
+5
+2
+2
+2
+8
+7
+2
+3
+8
+2
+6
+2
+2
+18
+2
+21
+2
+3
+2
+2
+2
+9
+3
+2
+2
+2
+2
+2
+2
+12
+3
+2
+15
+3
+3
+2
+2
+8
+3
+11
+17
+2
+2
+9
+2
+2
+2
+2
+2
+10
+8
+4
+4
+3
+2
+11
+21
+2
+18
+3
+17
+2
+3
+2
+23
+27
+18
+14
+16
+20
+2
+-1
+3
+2
+3
+2
+2
+10
+10
+3
+5
+2
+2
+2
+2
+2
+3
+2
+3
+2
+2
+2
+2
+9
+14
+2
+3
+10
+2
+3
+2
+2
+3
+2
+10
+15
+2
+15
+2
+2
+2
+2
+2
+3
+11
+16
+2
+12
+2
+10
+2
+5
+2
+2
+2
+3
+2
+2
+2
+-1
+2
+3
+2
+3
+7
+2
+3
+16
+2
+16
+3
+2
+3
+3
+4
+5
+2
+2
+2
+2
+2
+3
+5
+2
+9
+17
+8
+2
+2
+3
+2
+2
+3
+10
+3
+2
+2
+3
+19
+9
+2
+3
+2
+20
+2
+2
+2
+15
+2
+14
+2
+2
+22
+7
+9
+2
+2
+2
+9
+2
+2
+2
+2
+-1
+2
+2
+9
+3
+13
+2
+2
+12
+2
+2
+2
+3
+2
+2
+16
+3
+3
+3
+2
+4
+2
+2
+2
+2
+2
+5
+2
+2
+2
+2
+2
+2
+2
+2
+2
+7
+11
+2
+2
+3
+2
+11
+3
+8
+3
+2
+2
+11
+2
+2
+3
+3
+2
+2
+2
+2
+2
+18
+3
+2
+3
+2
+3
+2
+2
+2
+3
+2
+7
+3
+2
+2
+2
+3
+2
+9
+2
+3
+2
+2
+2
+2
+3
+13
+3
+2
+10
+2
+19
+3
+2
+3
+10
+3
+2
+2
+3
+3
+7
+2
+4
+2
+3
+2
+2
+2
+14
+15
+2
+2
+2
+3
+16
+2
+2
+2
+3
+2
+5
+14
+3
+4
+3
+2
+2
+3
+3
+10
+2
+8
+2
+19
+2
+2
+4
+2
+2
+11
+2
+2
+2
+3
+3
+7
+28
+2
+2
+9
+2
+2
+3
+3
+2
+2
+3
+9
+2
+16
+16
+3
+6
+3
+10
+2
+2
+2
+2
+2
+2
+2
+6
+2
+3
+3
+11
+2
+2
+3
+2
+2
+2
+2
+2
+3
+2
+3
+5
+2
+2
+2
+2
+3
+2
+2
+2
+2
+2
+7
+2
+2
+7
+13
+2
+2
+14
+2
+2
+2
+2
+2
+14
+2
+9
+10
+2
+2
+13
+2
+10
+2
+3
+2
+3
+6
+3
+2
+13
+2
+2
+2
+2
+15
+2
+2
+2
+9
+5
+2
+6
+4
+21
+2
+16
+2
+2
+2
+2
+2
+2
+2
+8
+5
+2
+2
+3
+5
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+27
+2
+2
+2
+3
+2
+13
+2
+11
+12
+12
+2
+18
+12
+3
+2
+13
+16
+2
+9
+22
+2
+2
+7
+2
+15
+2
+2
+2
+2
+12
+5
+2
+2
+2
+2
+2
+2
+2
+2
+7
+2
+6
+2
+5
+16
+2
+2
+9
+2
+2
+11
+2
+11
+31
+2
+14
+21
+2
+2
+2
+9
+2
+2
+2
+2
+2
+3
+3
+2
+2
+2
+2
+2
+6
+2
+3
+2
+2
+3
+2
+2
+10
+2
+2
+13
+38
+2
+2
+11
+12
+13
+2
+9
+2
+7
+13
+2
+2
+2
+3
+7
+2
+3
+2
+32
+2
+2
+2
+8
+9
+3
+2
+2
+3
+2
+17
+2
+4
+2
+3
+2
+2
+5
+2
+3
+3
+2
+3
+10
+4
+2
+2
+2
+20
+2
+13
+2
+2
+3
+2
+2
+16
+2
+4
+2
+7
+2
+2
+3
+3
+15
+2
+2
+2
+2
+3
+2
+2
+28
+2
+22
+2
+2
+2
+2
+12
+2
+11
+3
+2
+30
+10
+10
+41
+4
+15
+2
+3
+26
+3
+2
+2
+2
+2
+16
+3
+2
+2
+6
+2
+2
+3
+3
+2
+2
+2
+2
+3
+2
+2
+4
+2
+2
+12
+2
+2
+5
+2
+2
+2
+2
+3
+2
+5
+3
+3
+19
+2
+2
+6
+2
+2
+13
+3
+9
+3
+2
+3
+14
+3
+11
+3
+2
+18
+15
+3
+12
+27
+2
+2
+2
+3
+3
+2
+18
+9
+3
+13
+2
+2
+2
+9
+2
+2
+2
+2
+3
+3
+2
+7
+9
+4
+3
+8
+2
+7
+2
+10
+13
+2
+3
+2
+2
+16
+2
+26
+9
+26
+2
+11
+13
+2
+3
+9
+2
+3
+2
+2
+2
+2
+2
+3
+2
+3
+3
+5
+2
+2
+10
+2
+6
+2
+18
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+7
+4
+4
+8
+16
+3
+2
+2
+3
+2
+2
+3
+2
+2
+16
+2
+2
+2
+10
+2
+20
+2
+2
+2
+21
+3
+2
+2
+3
+2
+3
+3
+2
+3
+3
+2
+2
+3
+8
+2
+2
+2
+3
+2
+28
+2
+3
+15
diff --git a/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus_10000.txt b/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus_10000.txt
new file mode 100644
index 0000000..ea6c439
--- /dev/null
+++ b/python/plots/how_many_generations/data/k_graphs/how_many_generations_nikolaus_10000.txt
@@ -0,0 +1,10000 @@
+11
+3
+3
+11
+10
+2
+23
+2
+7
+15
+2
+2
+6
+3
+15
+20
+2
+3
+2
+2
+3
+12
+2
+13
+7
+3
+2
+2
+3
+2
+25
+3
+2
+21
+2
+14
+2
+13
+12
+28
+12
+15
+2
+2
+3
+7
+-1
+9
+18
+2
+2
+3
+19
+14
+2
+3
+2
+2
+18
+4
+13
+11
+7
+16
+2
+3
+2
+2
+2
+6
+15
+9
+2
+2
+2
+6
+3
+28
+11
+15
+2
+2
+2
+3
+3
+2
+2
+2
+2
+2
+6
+2
+11
+3
+2
+17
+2
+13
+3
+2
+2
+8
+2
+2
+2
+2
+2
+2
+2
+19
+2
+2
+2
+8
+3
+3
+2
+2
+2
+2
+2
+9
+2
+3
+2
+2
+2
+2
+12
+3
+3
+3
+5
+2
+3
+21
+3
+14
+5
+3
+2
+2
+2
+3
+2
+3
+9
+2
+2
+29
+2
+9
+13
+2
+2
+2
+2
+3
+3
+7
+2
+24
+13
+2
+2
+2
+7
+2
+3
+5
+2
+7
+2
+2
+16
+2
+9
+2
+10
+15
+2
+2
+2
+10
+2
+2
+3
+12
+18
+3
+10
+2
+2
+2
+2
+17
+3
+3
+2
+2
+12
+12
+2
+17
+2
+2
+3
+3
+2
+14
+2
+2
+9
+8
+3
+2
+7
+2
+-1
+2
+2
+2
+2
+9
+2
+2
+2
+2
+2
+6
+3
+2
+15
+2
+2
+17
+12
+5
+3
+3
+20
+2
+3
+2
+2
+2
+3
+3
+2
+5
+3
+2
+20
+2
+2
+22
+2
+13
+8
+2
+3
+3
+2
+2
+2
+15
+2
+10
+2
+24
+3
+2
+3
+2
+2
+3
+12
+2
+2
+4
+4
+2
+4
+3
+2
+2
+3
+8
+8
+9
+2
+3
+2
+12
+3
+2
+2
+3
+22
+12
+6
+2
+23
+2
+3
+2
+2
+3
+2
+2
+3
+3
+2
+3
+2
+3
+2
+2
+7
+3
+2
+15
+8
+2
+2
+3
+3
+2
+4
+2
+3
+2
+2
+3
+2
+21
+2
+2
+2
+2
+2
+2
+13
+2
+9
+2
+14
+22
+3
+2
+3
+6
+27
+2
+3
+2
+3
+12
+2
+2
+2
+2
+2
+3
+2
+3
+2
+21
+3
+3
+2
+8
+8
+2
+7
+2
+2
+2
+9
+2
+16
+2
+2
+2
+2
+3
+2
+9
+3
+3
+22
+2
+2
+8
+10
+2
+2
+3
+8
+2
+2
+9
+2
+6
+3
+2
+-1
+3
+7
+3
+2
+28
+9
+2
+2
+2
+2
+3
+2
+12
+8
+13
+2
+2
+2
+2
+2
+18
+7
+2
+2
+2
+2
+2
+6
+2
+2
+2
+2
+3
+3
+2
+2
+2
+2
+3
+3
+2
+2
+2
+8
+2
+2
+2
+2
+3
+2
+16
+2
+2
+3
+2
+5
+2
+13
+2
+2
+3
+15
+2
+9
+8
+7
+-1
+2
+2
+3
+2
+2
+14
+3
+2
+2
+2
+2
+6
+2
+2
+9
+2
+5
+16
+2
+2
+14
+2
+19
+5
+5
+2
+2
+9
+2
+2
+25
+10
+2
+19
+2
+2
+-1
+2
+2
+3
+3
+2
+2
+3
+2
+3
+10
+3
+2
+3
+9
+3
+2
+2
+18
+2
+7
+17
+2
+2
+3
+2
+2
+2
+2
+15
+4
+2
+3
+3
+3
+9
+2
+2
+12
+2
+3
+22
+2
+2
+2
+9
+15
+3
+5
+3
+10
+10
+3
+2
+3
+2
+11
+14
+3
+20
+2
+4
+9
+2
+3
+2
+2
+2
+2
+2
+29
+3
+9
+4
+2
+3
+3
+2
+2
+2
+16
+3
+4
+2
+18
+3
+2
+2
+2
+2
+5
+2
+3
+2
+2
+4
+15
+11
+21
+2
+2
+3
+7
+9
+2
+10
+2
+6
+3
+2
+2
+2
+2
+12
+2
+2
+3
+13
+2
+2
+12
+2
+2
+2
+2
+2
+10
+9
+4
+4
+5
+3
+8
+4
+2
+3
+3
+9
+2
+2
+8
+3
+2
+3
+18
+2
+3
+5
+2
+2
+2
+2
+2
+2
+19
+4
+3
+16
+2
+2
+2
+16
+2
+19
+2
+10
+2
+2
+9
+2
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+3
+2
+10
+2
+6
+3
+3
+2
+2
+2
+2
+2
+2
+3
+2
+5
+2
+2
+2
+2
+2
+2
+2
+2
+15
+2
+2
+14
+2
+2
+8
+2
+2
+10
+2
+14
+3
+7
+10
+10
+2
+16
+2
+2
+2
+2
+2
+3
+2
+15
+12
+2
+16
+14
+13
+8
+6
+2
+2
+6
+2
+2
+2
+2
+2
+3
+9
+8
+3
+2
+3
+2
+4
+3
+20
+2
+2
+7
+3
+2
+2
+3
+2
+2
+3
+2
+2
+19
+2
+2
+2
+13
+2
+2
+2
+3
+11
+15
+2
+12
+11
+2
+28
+8
+12
+17
+25
+6
+2
+2
+21
+2
+2
+2
+4
+15
+2
+2
+14
+3
+13
+20
+2
+-1
+2
+9
+11
+2
+2
+2
+2
+11
+2
+2
+5
+2
+8
+3
+3
+3
+2
+8
+11
+7
+2
+2
+2
+2
+2
+2
+2
+2
+6
+2
+7
+15
+9
+18
+2
+37
+3
+14
+2
+2
+4
+2
+3
+2
+2
+2
+2
+24
+2
+2
+2
+3
+2
+8
+2
+2
+3
+3
+2
+2
+2
+4
+3
+2
+3
+24
+12
+2
+5
+2
+3
+2
+2
+2
+2
+3
+2
+2
+16
+32
+2
+2
+5
+3
+2
+2
+2
+2
+2
+10
+3
+2
+2
+5
+5
+5
+3
+12
+2
+2
+2
+3
+2
+18
+9
+2
+3
+2
+12
+2
+3
+2
+2
+2
+7
+3
+3
+2
+2
+2
+2
+14
+2
+3
+25
+17
+17
+6
+17
+12
+10
+2
+28
+11
+12
+8
+2
+3
+3
+9
+4
+14
+16
+2
+2
+3
+13
+2
+17
+6
+2
+2
+2
+10
+5
+3
+12
+2
+2
+10
+3
+2
+4
+7
+14
+2
+2
+2
+6
+2
+4
+10
+2
+5
+8
+10
+8
+5
+2
+4
+3
+3
+2
+2
+3
+28
+14
+5
+5
+3
+3
+2
+13
+2
+3
+2
+2
+2
+2
+4
+4
+3
+17
+6
+2
+2
+10
+3
+2
+2
+2
+12
+3
+2
+2
+10
+3
+8
+3
+2
+3
+15
+2
+11
+6
+2
+2
+24
+19
+11
+2
+3
+11
+3
+2
+7
+2
+2
+2
+19
+8
+2
+2
+2
+2
+10
+2
+3
+5
+10
+2
+2
+2
+2
+6
+5
+11
+12
+15
+9
+2
+2
+2
+3
+3
+2
+4
+9
+16
+3
+3
+14
+3
+16
+3
+4
+17
+19
+3
+2
+2
+2
+2
+5
+2
+2
+2
+2
+2
+11
+15
+19
+2
+3
+2
+2
+5
+3
+2
+2
+3
+3
+2
+3
+13
+6
+2
+2
+2
+3
+2
+10
+5
+2
+2
+2
+11
+2
+3
+2
+11
+3
+3
+2
+3
+2
+9
+2
+2
+2
+3
+20
+12
+10
+3
+5
+3
+2
+27
+2
+18
+2
+10
+2
+18
+3
+2
+9
+5
+2
+2
+4
+3
+7
+4
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+2
+2
+2
+-1
+3
+2
+5
+2
+2
+4
+3
+2
+2
+2
+2
+2
+2
+2
+2
+3
+2
+3
+6
+2
+2
+2
+2
+16
+3
+2
+9
+2
+3
+2
+14
+2
+2
+8
+12
+24
+2
+8
+13
+2
+2
+2
+2
+16
+2
+3
+2
+2
+2
+2
+2
+2
+21
+2
+3
+6
+11
+3
+2
+8
+2
+2
+-1
+2
+2
+2
+2
+24
+3
+2
+2
+6
+2
+20
+2
+2
+3
+2
+2
+2
+11
+3
+2
+2
+5
+2
+2
+3
+21
+2
+2
+20
+2
+11
+2
+3
+5
+2
+2
+3
+16
+19
+4
+4
+2
+2
+2
+5
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+2
+2
+2
+16
+2
+6
+11
+12
+7
+4
+2
+3
+2
+2
+2
+2
+2
+3
+15
+13
+3
+2
+2
+7
+2
+2
+16
+2
+2
+3
+2
+2
+2
+9
+6
+9
+19
+3
+3
+16
+2
+8
+3
+2
+2
+2
+2
+2
+-1
+2
+2
+3
+12
+4
+13
+3
+14
+3
+11
+9
+2
+11
+2
+3
+5
+2
+3
+14
+2
+2
+2
+2
+2
+3
+2
+9
+16
+3
+2
+3
+18
+2
+2
+13
+2
+21
+2
+8
+3
+15
+9
+2
+3
+3
+2
+2
+2
+2
+2
+2
+2
+11
+2
+5
+2
+3
+8
+3
+4
+2
+2
+19
+2
+16
+3
+2
+2
+14
+12
+2
+3
+12
+2
+2
+2
+2
+2
+3
+3
+2
+2
+-1
+2
+3
+5
+2
+3
+2
+2
+2
+23
+17
+13
+2
+3
+2
+2
+2
+3
+2
+3
+3
+2
+10
+2
+3
+2
+3
+2
+3
+2
+2
+3
+2
+2
+3
+28
+2
+2
+9
+3
+2
+2
+12
+9
+2
+9
+3
+2
+17
+2
+3
+2
+17
+2
+2
+2
+2
+3
+2
+17
+3
+13
+2
+6
+8
+15
+11
+3
+2
+2
+2
+3
+12
+18
+3
+23
+2
+15
+2
+2
+2
+3
+17
+2
+14
+-1
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+11
+18
+2
+19
+2
+2
+2
+2
+2
+2
+2
+8
+2
+2
+2
+6
+2
+3
+3
+3
+16
+3
+2
+2
+2
+2
+10
+2
+22
+2
+11
+2
+4
+2
+2
+18
+2
+3
+2
+2
+3
+2
+2
+11
+2
+3
+4
+3
+2
+2
+2
+3
+2
+6
+2
+3
+3
+2
+12
+2
+2
+2
+5
+2
+3
+2
+2
+2
+4
+2
+11
+2
+2
+18
+2
+3
+16
+3
+16
+3
+3
+2
+2
+2
+2
+2
+2
+8
+13
+2
+2
+3
+3
+2
+2
+3
+5
+2
+4
+2
+2
+16
+2
+8
+11
+2
+15
+2
+2
+13
+4
+2
+3
+2
+2
+2
+4
+3
+2
+10
+14
+2
+2
+19
+14
+2
+2
+5
+2
+7
+2
+6
+2
+2
+18
+2
+3
+14
+2
+2
+8
+2
+2
+2
+8
+3
+2
+8
+18
+2
+2
+2
+19
+2
+2
+25
+14
+3
+2
+6
+12
+21
+2
+2
+3
+3
+2
+2
+2
+2
+19
+5
+6
+2
+2
+2
+15
+2
+2
+3
+2
+4
+2
+2
+3
+2
+9
+7
+2
+10
+2
+2
+3
+45
+3
+3
+3
+2
+2
+2
+2
+4
+6
+2
+2
+8
+26
+2
+6
+3
+2
+2
+14
+12
+2
+8
+3
+7
+3
+2
+3
+3
+3
+3
+11
+12
+3
+3
+2
+2
+2
+2
+3
+2
+2
+2
+3
+22
+-1
+3
+2
+2
+2
+2
+2
+4
+2
+24
+4
+3
+2
+6
+2
+2
+2
+11
+2
+-1
+2
+2
+6
+3
+2
+3
+2
+6
+2
+17
+2
+2
+6
+2
+10
+2
+2
+3
+2
+2
+2
+17
+9
+4
+2
+6
+7
+2
+2
+2
+2
+2
+3
+2
+3
+23
+2
+2
+22
+3
+2
+2
+-1
+2
+16
+3
+2
+2
+2
+3
+2
+3
+9
+16
+2
+2
+3
+2
+2
+2
+2
+11
+3
+2
+2
+2
+3
+2
+25
+10
+2
+18
+2
+2
+2
+3
+3
+18
+11
+2
+2
+2
+2
+4
+2
+8
+5
+2
+2
+2
+2
+2
+2
+7
+2
+2
+2
+2
+-1
+2
+2
+3
+2
+3
+9
+2
+2
+2
+2
+15
+2
+2
+2
+2
+2
+11
+3
+2
+2
+2
+2
+13
+2
+3
+2
+17
+3
+2
+2
+3
+4
+3
+2
+16
+8
+2
+8
+3
+2
+17
+11
+9
+2
+31
+4
+3
+2
+3
+2
+12
+2
+2
+2
+2
+2
+3
+2
+5
+2
+2
+3
+2
+2
+12
+2
+2
+8
+3
+2
+2
+10
+10
+19
+2
+4
+3
+3
+21
+2
+8
+2
+2
+2
+2
+4
+2
+5
+2
+5
+3
+9
+2
+11
+3
+2
+3
+2
+4
+21
+2
+9
+2
+21
+2
+19
+2
+2
+3
+2
+2
+18
+2
+3
+2
+2
+2
+2
+25
+2
+2
+2
+2
+2
+12
+3
+4
+3
+2
+2
+19
+4
+4
+8
+3
+3
+8
+2
+3
+2
+2
+2
+20
+11
+3
+20
+2
+17
+2
+2
+2
+2
+2
+3
+3
+3
+2
+4
+2
+2
+7
+3
+5
+6
+2
+7
+8
+2
+2
+2
+4
+2
+13
+2
+10
+2
+3
+14
+3
+14
+2
+2
+14
+2
+13
+16
+2
+2
+6
+3
+2
+16
+8
+21
+11
+2
+5
+2
+2
+2
+3
+5
+7
+6
+11
+2
+3
+8
+2
+2
+2
+2
+8
+3
+2
+2
+2
+15
+2
+2
+3
+2
+9
+2
+2
+3
+10
+3
+2
+2
+2
+2
+19
+11
+2
+30
+3
+2
+3
+3
+2
+19
+6
+-1
+2
+2
+12
+2
+3
+9
+2
+2
+3
+11
+2
+3
+2
+2
+13
+3
+2
+2
+2
+9
+2
+2
+10
+3
+3
+2
+5
+12
+2
+3
+2
+2
+2
+3
+9
+2
+2
+15
+3
+3
+14
+2
+2
+3
+2
+2
+2
+3
+3
+2
+2
+2
+2
+2
+2
+17
+2
+3
+2
+2
+2
+2
+2
+4
+2
+3
+3
+2
+2
+3
+2
+9
+2
+2
+2
+2
+10
+2
+2
+2
+3
+2
+19
+8
+2
+2
+2
+3
+2
+8
+41
+2
+2
+2
+13
+9
+19
+2
+2
+6
+3
+7
+17
+2
+2
+2
+9
+2
+2
+10
+2
+2
+3
+2
+2
+2
+4
+2
+18
+2
+10
+2
+2
+34
+2
+12
+20
+2
+2
+8
+2
+2
+2
+9
+13
+3
+10
+3
+2
+2
+3
+3
+5
+8
+2
+2
+2
+7
+2
+6
+3
+2
+2
+8
+2
+2
+3
+2
+2
+14
+3
+2
+6
+2
+28
+19
+2
+6
+10
+2
+3
+2
+3
+2
+37
+10
+2
+3
+2
+2
+12
+2
+7
+5
+14
+2
+10
+11
+2
+3
+9
+2
+6
+2
+2
+3
+3
+2
+2
+2
+2
+3
+2
+2
+2
+18
+2
+2
+3
+2
+4
+2
+27
+2
+2
+10
+2
+11
+2
+15
+2
+3
+3
+8
+6
+3
+2
+2
+17
+2
+14
+4
+2
+3
+17
+2
+4
+2
+2
+2
+2
+10
+3
+2
+10
+7
+2
+2
+2
+2
+2
+2
+16
+3
+2
+4
+32
+17
+23
+2
+14
+3
+2
+3
+2
+13
+2
+3
+3
+2
+2
+2
+5
+2
+2
+2
+10
+2
+6
+2
+3
+3
+2
+24
+2
+3
+2
+11
+3
+22
+2
+2
+3
+3
+2
+2
+2
+5
+2
+2
+2
+2
+2
+6
+2
+2
+24
+3
+2
+3
+6
+2
+4
+2
+2
+11
+2
+9
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+13
+3
+3
+30
+2
+4
+15
+2
+2
+2
+3
+2
+2
+3
+2
+19
+2
+2
+2
+3
+2
+2
+2
+2
+6
+2
+6
+19
+2
+2
+3
+7
+3
+12
+2
+4
+2
+2
+2
+2
+2
+2
+2
+2
+2
+7
+2
+2
+2
+12
+4
+6
+8
+2
+2
+2
+16
+17
+2
+3
+2
+12
+2
+2
+2
+3
+10
+2
+2
+2
+6
+2
+3
+3
+3
+5
+13
+11
+2
+2
+8
+14
+6
+3
+17
+2
+3
+2
+12
+2
+2
+2
+2
+6
+3
+8
+2
+2
+3
+3
+3
+7
+2
+4
+2
+4
+12
+22
+2
+3
+2
+10
+2
+2
+3
+2
+2
+9
+2
+2
+2
+3
+2
+3
+2
+2
+2
+2
+2
+2
+2
+3
+3
+2
+3
+18
+2
+3
+11
+2
+8
+6
+2
+2
+20
+3
+19
+2
+9
+3
+2
+17
+13
+2
+5
+2
+2
+3
+3
+10
+2
+2
+8
+25
+17
+2
+3
+2
+2
+4
+3
+2
+-1
+3
+3
+2
+2
+20
+3
+4
+2
+3
+2
+2
+11
+2
+10
+2
+2
+2
+2
+2
+2
+11
+2
+2
+3
+10
+2
+3
+8
+3
+3
+2
+-1
+13
+3
+2
+3
+2
+28
+3
+17
+3
+3
+26
+2
+6
+2
+2
+2
+2
+2
+3
+2
+5
+2
+11
+2
+2
+10
+4
+2
+2
+3
+3
+2
+2
+2
+2
+2
+9
+3
+2
+2
+2
+3
+2
+2
+4
+2
+2
+2
+2
+11
+3
+2
+17
+2
+2
+14
+19
+2
+4
+3
+2
+7
+2
+2
+12
+2
+-1
+2
+3
+3
+3
+3
+2
+2
+3
+7
+2
+2
+2
+2
+15
+3
+2
+2
+5
+4
+2
+2
+10
+2
+2
+9
+2
+2
+2
+10
+15
+8
+2
+2
+2
+13
+2
+2
+3
+3
+13
+14
+8
+2
+11
+2
+7
+2
+13
+30
+24
+2
+2
+3
+2
+3
+2
+2
+3
+14
+13
+15
+2
+2
+45
+3
+6
+16
+20
+2
+33
+2
+18
+2
+2
+2
+3
+11
+2
+10
+3
+17
+3
+2
+2
+2
+28
+14
+2
+2
+8
+4
+2
+3
+2
+2
+6
+14
+7
+3
+2
+14
+2
+15
+6
+2
+3
+16
+10
+11
+2
+2
+2
+3
+3
+2
+2
+2
+2
+3
+3
+3
+2
+8
+2
+3
+13
+3
+2
+10
+2
+17
+2
+14
+2
+2
+2
+13
+2
+2
+2
+19
+17
+2
+2
+24
+2
+3
+8
+2
+2
+2
+2
+2
+2
+5
+2
+2
+2
+5
+3
+2
+2
+3
+2
+2
+3
+2
+2
+3
+2
+2
+15
+11
+10
+2
+2
+2
+13
+2
+2
+3
+8
+2
+2
+2
+12
+2
+8
+2
+3
+2
+8
+11
+3
+5
+15
+15
+9
+2
+3
+2
+2
+2
+2
+12
+2
+15
+2
+12
+2
+2
+2
+2
+3
+2
+12
+2
+2
+2
+2
+19
+2
+3
+2
+2
+2
+19
+2
+3
+3
+7
+3
+2
+22
+2
+2
+2
+2
+2
+8
+2
+2
+2
+3
+32
+2
+3
+12
+2
+4
+4
+2
+15
+10
+2
+2
+2
+3
+2
+18
+18
+3
+17
+3
+2
+9
+6
+2
+2
+2
+10
+17
+3
+2
+10
+2
+6
+3
+2
+6
+2
+2
+2
+2
+9
+6
+18
+2
+2
+2
+2
+3
+2
+2
+10
+3
+7
+3
+19
+2
+5
+6
+11
+2
+2
+2
+8
+2
+2
+2
+2
+2
+2
+17
+2
+2
+3
+2
+2
+3
+2
+12
+2
+6
+2
+3
+3
+2
+2
+8
+25
+2
+2
+3
+6
+3
+18
+20
+2
+2
+3
+2
+3
+3
+8
+2
+6
+2
+2
+2
+2
+8
+2
+2
+2
+2
+2
+2
+2
+10
+3
+2
+2
+4
+13
+7
+2
+2
+2
+3
+2
+11
+2
+2
+2
+5
+3
+2
+10
+2
+2
+15
+3
+3
+10
+18
+16
+7
+2
+3
+2
+2
+17
+10
+2
+2
+2
+2
+3
+5
+2
+2
+10
+2
+8
+3
+2
+3
+16
+3
+2
+3
+2
+2
+2
+3
+2
+2
+3
+2
+14
+3
+3
+14
+2
+2
+2
+12
+11
+2
+2
+2
+3
+2
+2
+2
+12
+2
+4
+2
+15
+2
+15
+8
+2
+2
+16
+3
+3
+3
+2
+2
+3
+2
+2
+3
+2
+11
+2
+4
+3
+2
+2
+2
+18
+-1
+2
+2
+3
+2
+4
+3
+2
+11
+11
+2
+3
+6
+2
+8
+12
+2
+3
+6
+2
+3
+3
+4
+2
+2
+3
+2
+3
+3
+2
+5
+2
+2
+2
+2
+2
+3
+2
+2
+2
+11
+2
+11
+2
+3
+3
+10
+2
+2
+15
+11
+2
+2
+2
+19
+8
+2
+2
+2
+2
+2
+2
+10
+2
+3
+9
+3
+6
+2
+10
+2
+2
+2
+2
+3
+3
+18
+2
+10
+2
+11
+3
+2
+3
+2
+9
+4
+3
+2
+2
+2
+3
+2
+15
+3
+2
+2
+2
+2
+12
+3
+2
+14
+10
+21
+5
+2
+5
+2
+2
+2
+2
+7
+2
+2
+2
+2
+2
+2
+4
+2
+2
+2
+2
+2
+3
+3
+6
+2
+2
+2
+2
+2
+3
+3
+2
+7
+2
+2
+2
+15
+2
+13
+9
+2
+8
+17
+17
+2
+2
+2
+2
+8
+3
+7
+5
+3
+2
+2
+8
+8
+2
+2
+2
+2
+12
+3
+2
+2
+2
+3
+2
+3
+2
+2
+2
+2
+16
+2
+2
+2
+3
+2
+2
+3
+2
+2
+2
+2
+7
+3
+2
+2
+2
+2
+10
+2
+19
+2
+2
+3
+4
+2
+2
+2
+9
+2
+2
+2
+3
+3
+2
+2
+2
+4
+28
+2
+3
+2
+18
+3
+17
+9
+2
+3
+10
+2
+3
+2
+2
+2
+3
+3
+15
+8
+3
+2
+2
+21
+15
+2
+27
+2
+15
+30
+20
+2
+3
+2
+2
+2
+19
+3
+2
+3
+2
+9
+2
+2
+12
+9
+11
+2
+3
+2
+2
+4
+7
+3
+3
+22
+3
+10
+2
+2
+2
+3
+10
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+18
+2
+2
+2
+2
+2
+2
+2
+3
+9
+3
+2
+2
+18
+9
+2
+2
+2
+13
+2
+3
+2
+2
+20
+3
+2
+13
+2
+3
+7
+2
+2
+2
+11
+10
+3
+3
+2
+3
+3
+2
+2
+2
+14
+3
+2
+3
+15
+9
+2
+32
+2
+2
+14
+2
+2
+2
+3
+2
+2
+9
+26
+2
+19
+2
+2
+2
+3
+2
+2
+2
+2
+2
+11
+6
+2
+4
+18
+2
+32
+9
+8
+2
+2
+8
+3
+8
+2
+9
+2
+3
+7
+2
+2
+2
+2
+3
+3
+2
+2
+2
+2
+9
+2
+2
+5
+2
+8
+2
+17
+13
+3
+31
+28
+2
+2
+2
+3
+3
+2
+2
+6
+25
+2
+3
+16
+3
+9
+14
+2
+9
+26
+3
+2
+3
+2
+3
+10
+2
+2
+44
+2
+2
+14
+2
+2
+4
+22
+2
+6
+9
+2
+3
+3
+2
+4
+2
+10
+2
+3
+2
+3
+3
+2
+2
+23
+2
+3
+22
+3
+2
+2
+3
+2
+2
+2
+11
+19
+2
+2
+3
+7
+4
+2
+2
+2
+3
+18
+12
+40
+3
+10
+3
+2
+2
+2
+2
+3
+2
+2
+4
+14
+2
+11
+12
+12
+2
+11
+2
+3
+2
+8
+2
+15
+2
+2
+2
+2
+5
+11
+2
+4
+4
+2
+2
+14
+5
+9
+13
+2
+2
+3
+5
+2
+30
+3
+4
+2
+2
+2
+31
+2
+2
+3
+2
+16
+2
+2
+2
+2
+2
+8
+2
+2
+2
+2
+2
+2
+11
+3
+2
+4
+15
+28
+17
+3
+-1
+33
+2
+2
+11
+2
+4
+14
+13
+8
+2
+2
+2
+3
+2
+3
+5
+3
+2
+2
+2
+2
+2
+2
+2
+2
+7
+2
+20
+16
+2
+2
+5
+2
+2
+2
+2
+6
+2
+2
+8
+2
+16
+6
+10
+3
+2
+14
+8
+2
+2
+13
+3
+2
+2
+2
+3
+2
+9
+8
+2
+3
+13
+11
+5
+17
+2
+7
+20
+2
+3
+6
+22
+2
+3
+2
+2
+2
+2
+2
+11
+4
+2
+4
+8
+2
+3
+2
+2
+2
+2
+16
+2
+2
+7
+2
+2
+5
+37
+2
+2
+2
+7
+2
+13
+3
+7
+2
+6
+40
+15
+3
+2
+14
+4
+2
+4
+2
+15
+2
+2
+8
+3
+2
+4
+11
+2
+2
+3
+2
+11
+10
+2
+7
+2
+2
+3
+2
+2
+7
+11
+2
+2
+7
+3
+2
+2
+15
+-1
+3
+9
+2
+2
+28
+2
+2
+3
+-1
+3
+21
+15
+2
+6
+12
+2
+3
+2
+2
+3
+3
+2
+4
+2
+2
+2
+6
+2
+2
+2
+2
+2
+2
+9
+7
+2
+10
+18
+5
+15
+5
+11
+2
+3
+2
+2
+10
+2
+2
+12
+3
+2
+2
+21
+2
+3
+2
+4
+3
+3
+6
+8
+15
+11
+2
+2
+2
+23
+12
+2
+18
+2
+2
+4
+2
+2
+17
+2
+2
+2
+2
+13
+5
+2
+3
+2
+11
+24
+8
+2
+-1
+3
+9
+2
+2
+21
+2
+2
+2
+2
+2
+2
+4
+2
+10
+16
+7
+2
+14
+46
+3
+5
+2
+2
+3
+3
+2
+4
+2
+17
+2
+6
+8
+2
+23
+2
+2
+16
+2
+2
+9
+2
+6
+3
+9
+2
+2
+2
+2
+12
+3
+12
+12
+2
+3
+2
+2
+6
+5
+3
+3
+2
+3
+2
+3
+2
+2
+7
+8
+9
+6
+3
+2
+3
+8
+2
+17
+3
+19
+2
+2
+3
+2
+3
+4
+10
+2
+3
+3
+4
+3
+7
+4
+2
+2
+2
+2
+3
+5
+14
+2
+2
+2
+2
+4
+3
+2
+3
+2
+2
+3
+13
+2
+13
+2
+2
+2
+2
+11
+2
+7
+2
+3
+2
+14
+3
+10
+18
+8
+2
+20
+2
+2
+2
+2
+2
+3
+3
+3
+2
+2
+2
+7
+2
+8
+2
+8
+2
+3
+3
+3
+18
+4
+2
+3
+5
+2
+3
+2
+2
+9
+3
+2
+11
+3
+3
+16
+3
+2
+16
+2
+3
+2
+8
+2
+2
+3
+2
+2
+2
+2
+2
+19
+2
+3
+3
+2
+2
+11
+33
+2
+2
+2
+2
+2
+19
+3
+2
+2
+2
+2
+2
+4
+9
+2
+10
+2
+2
+7
+3
+2
+2
+10
+2
+2
+20
+2
+18
+2
+2
+16
+4
+2
+9
+3
+2
+3
+2
+5
+2
+16
+19
+2
+3
+34
+8
+2
+2
+3
+2
+2
+2
+21
+2
+3
+2
+3
+3
+13
+11
+3
+2
+2
+3
+2
+18
+2
+59
+2
+3
+2
+2
+2
+2
+3
+3
+2
+3
+9
+16
+2
+2
+2
+2
+2
+2
+20
+2
+2
+5
+6
+2
+2
+2
+8
+5
+16
+2
+2
+2
+3
+2
+2
+3
+2
+2
+2
+7
+3
+2
+2
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+9
+4
+2
+13
+2
+2
+2
+3
+18
+2
+2
+2
+-1
+4
+2
+2
+3
+2
+11
+2
+12
+2
+2
+2
+24
+2
+4
+8
+8
+18
+2
+2
+2
+2
+7
+2
+6
+2
+12
+2
+3
+3
+16
+3
+10
+2
+2
+3
+2
+3
+16
+6
+7
+10
+13
+3
+2
+3
+2
+2
+11
+2
+2
+2
+2
+2
+2
+4
+4
+2
+10
+2
+3
+17
+18
+2
+12
+2
+21
+3
+10
+13
+2
+2
+2
+6
+2
+2
+2
+2
+3
+2
+2
+2
+2
+2
+3
+14
+8
+5
+3
+2
+3
+2
+3
+2
+3
+2
+3
+2
+2
+2
+2
+24
+2
+9
+2
+2
+4
+2
+14
+3
+5
+14
+2
+3
+30
+10
+15
+3
+2
+2
+9
+23
+2
+2
+2
+2
+2
+2
+3
+3
+15
+9
+8
+2
+2
+28
+2
+2
+27
+7
+10
+17
+2
+6
+2
+7
+2
+3
+2
+3
+2
+2
+8
+11
+7
+3
+11
+14
+2
+14
+2
+2
+3
+2
+3
+5
+17
+17
+2
+19
+3
+3
+3
+17
+2
+2
+8
+3
+3
+3
+9
+2
+2
+15
+2
+2
+2
+16
+3
+2
+2
+3
+2
+2
+2
+2
+3
+32
+2
+8
+2
+3
+4
+2
+10
+6
+8
+2
+4
+2
+2
+15
+2
+7
+2
+2
+2
+3
+4
+2
+2
+3
+14
+4
+2
+2
+2
+7
+3
+2
+2
+19
+2
+2
+3
+2
+2
+3
+10
+22
+2
+2
+2
+3
+2
+30
+9
+2
+2
+13
+2
+2
+2
+12
+2
+2
+3
+2
+21
+3
+11
+2
+4
+2
+2
+2
+2
+3
+2
+12
+3
+2
+2
+2
+3
+3
+2
+2
+2
+4
+14
+2
+2
+9
+6
+2
+3
+2
+2
+2
+2
+2
+2
+2
+9
+2
+3
+3
+3
+5
+2
+3
+2
+16
+4
+3
+2
+2
+3
+18
+2
+3
+2
+2
+2
+2
+2
+6
+2
+3
+3
+2
+2
+10
+-1
+2
+2
+3
+3
+3
+2
+2
+5
+2
+2
+2
+2
+2
+10
+17
+2
+8
+3
+12
+8
+2
+9
+21
+12
+13
+3
+2
+11
+3
+5
+2
+2
+2
+2
+7
+11
+2
+13
+2
+11
+8
+2
+2
+2
+2
+8
+2
+2
+2
+2
+3
+3
+26
+2
+2
+2
+7
+6
+2
+3
+2
+2
+2
+3
+3
+2
+3
+4
+3
+2
+17
+2
+3
+2
+14
+2
+10
+4
+10
+-1
+2
+2
+16
+3
+4
+2
+48
+2
+3
+3
+4
+2
+16
+23
+2
+2
+2
+14
+10
+2
+3
+2
+2
+6
+2
+5
+2
+2
+2
+2
+8
+12
+23
+2
+2
+10
+28
+2
+6
+3
+2
+2
+2
+2
+14
+3
+15
+2
+5
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+11
+7
+2
+3
+25
+-1
+2
+2
+2
+5
+7
+12
+2
+2
+3
+2
+2
+2
+-1
+2
+2
+3
+7
+3
+18
+7
+23
+12
+6
+14
+5
+3
+2
+2
+3
+3
+6
+2
+3
+2
+2
+10
+2
+16
+2
+2
+2
+2
+2
+2
+2
+7
+3
+2
+7
+5
+3
+2
+2
+3
+15
+10
+2
+8
+3
+2
+2
+3
+2
+2
+3
+3
+2
+2
+21
+17
+2
+2
+7
+2
+2
+2
+2
+2
+12
+2
+11
+2
+15
+3
+3
+2
+2
+11
+2
+2
+16
+2
+9
+3
+3
+2
+2
+3
+13
+7
+3
+2
+2
+12
+6
+2
+2
+3
+2
+7
+2
+20
+4
+2
+2
+2
+13
+11
+3
+11
+2
+8
+2
+14
+12
+2
+2
+3
+2
+21
+3
+12
+2
+26
+3
+9
+2
+2
+2
+-1
+8
+3
+6
+2
+2
+9
+28
+2
+3
+2
+30
+2
+5
+2
+3
+2
+-1
+3
+15
+6
+16
+2
+10
+2
+2
+2
+2
+2
+2
+4
+2
+5
+12
+3
+3
+2
+2
+2
+6
+2
+13
+2
+2
+12
+2
+2
+12
+3
+14
+2
+11
+2
+2
+2
+4
+2
+2
+2
+3
+11
+2
+2
+3
+19
+2
+3
+4
+2
+3
+2
+2
+2
+13
+3
+3
+14
+2
+2
+2
+12
+2
+14
+2
+3
+2
+2
+2
+14
+3
+3
+3
+2
+3
+6
+2
+2
+6
+8
+2
+20
+2
+9
+2
+3
+3
+21
+13
+2
+5
+6
+2
+5
+2
+2
+3
+2
+2
+9
+2
+14
+3
+2
+2
+3
+6
+5
+18
+2
+3
+2
+2
+3
+2
+2
+13
+12
+2
+2
+2
+2
+3
+2
+2
+19
+15
+4
+2
+2
+3
+10
+2
+2
+2
+3
+18
+7
+2
+2
+8
+2
+2
+2
+7
+2
+11
+2
+2
+10
+9
+-1
+7
+2
+2
+3
+2
+3
+2
+2
+4
+2
+8
+2
+8
+2
+15
+2
+2
+2
+2
+2
+2
+3
+2
+2
+2
+8
+2
+13
+2
+2
+2
+3
+6
+2
+16
+10
+11
+5
+2
+2
+2
+2
+9
+2
+22
+3
+2
+13
+3
+2
+2
+24
+19
+2
+2
+2
+2
+16
+2
+3
+3
+2
+21
+2
+3
+8
+4
+3
+2
+2
+3
+3
+2
+2
+2
+3
+2
+2
+19
+11
+2
+17
+2
+5
+2
+2
+9
+2
+3
+3
+2
+2
+2
+20
+16
+8
+7
+2
+2
+4
+2
+2
+3
+2
+2
+8
+8
+2
+2
+2
+2
+2
+12
+3
+2
+2
+2
+15
+-1
+2
+2
+2
+11
+20
+2
+40
+2
+9
+14
+9
+2
+2
+2
+21
+2
+-1
+4
+2
+2
+2
+3
+3
+2
+3
+2
+2
+5
+3
+2
+2
+3
+2
+3
+2
+5
+2
+2
+3
+2
+12
+3
+4
+2
+2
+2
+15
+2
+2
+2
+2
+-1
+12
+4
+3
+2
+10
+2
+11
+3
+2
+2
+2
+2
+2
+3
+4
+2
+11
+2
+2
+2
+16
+2
+18
+16
+2
+3
+3
+2
+2
+3
+3
+3
+12
+2
+10
+10
+2
+2
+2
+2
+21
+28
+2
+2
+2
+13
+20
+5
+12
+18
+2
+2
+2
+2
+17
+2
+2
+18
+2
+10
+2
+3
+12
+5
+19
+2
+2
+13
+2
+2
+3
+2
+2
+2
+2
+2
+8
+2
+2
+3
+10
+2
+7
+2
+2
+2
+14
+2
+2
+6
+2
+2
+3
+2
+15
+2
+2
+5
+2
+7
+3
+2
+2
+2
+11
+13
+20
+2
+2
+2
+2
+2
+3
+11
+2
+3
+2
+2
+2
+2
+2
+2
+2
+7
+3
+2
+2
+2
+16
+2
+13
+3
+10
+3
+2
+2
+22
+3
+3
+2
+2
+7
+2
+2
+2
+2
+23
+2
+9
+16
+3
+2
+7
+14
+2
+2
+2
+3
+2
+10
+2
+12
+5
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+9
+9
+3
+14
+2
+11
+3
+3
+2
+2
+2
+4
+2
+2
+5
+2
+3
+9
+2
+2
+15
+7
+2
+2
+12
+3
+2
+2
+3
+2
+17
+2
+2
+2
+2
+3
+14
+3
+18
+15
+3
+14
+2
+6
+15
+2
+2
+2
+2
+-1
+2
+10
+2
+-1
+2
+37
+22
+4
+-1
+2
+2
+3
+6
+3
+2
+2
+30
+2
+2
+3
+2
+2
+2
+2
+32
+2
+2
+22
+2
+3
+3
+2
+3
+4
+2
+2
+12
+3
+2
+9
+2
+9
+2
+2
+2
+12
+15
+2
+2
+2
+3
+2
+3
+2
+6
+4
+2
+2
+13
+8
+5
+2
+2
+2
+2
+3
+3
+2
+2
+2
+23
+3
+3
+2
+3
+2
+3
+3
+3
+2
+2
+2
+6
+2
+2
+2
+3
+2
+2
+2
+2
+2
+3
+8
+8
+15
+2
+2
+12
+15
+3
+2
+2
+17
+2
+3
+2
+3
+3
+2
+2
+19
+7
+3
+17
+6
+2
+2
+2
+2
+2
+2
+4
+3
+16
+2
+2
+2
+2
+2
+2
+16
+3
+11
+2
+2
+8
+19
+3
+2
+3
+12
+2
+2
+2
+2
+4
+3
+2
+2
+2
+2
+3
+6
+2
+2
+2
+2
+3
+10
+2
+7
+12
+2
+2
+11
+2
+11
+2
+2
+3
+2
+16
+2
+10
+2
+12
+2
+2
+17
+2
+2
+4
+2
+2
+6
+3
+2
+3
+2
+2
+3
+2
+12
+13
+2
+2
+16
+2
+2
+2
+2
+9
+6
+3
+2
+12
+-1
+2
+2
+2
+2
+10
+2
+3
+2
+22
+2
+2
+2
+11
+2
+2
+12
+2
+2
+3
+2
+2
+2
+3
+3
+2
+7
+30
+19
+3
+2
+3
+13
+2
+2
+21
+3
+3
+2
+7
+2
+3
+23
+10
+2
+3
+3
+2
+2
+2
+2
+3
+2
+3
+6
+3
+2
+2
+2
+14
+2
+2
+2
+2
+4
+2
+3
+2
+2
+2
+3
+2
+2
+2
+3
+3
+2
+2
+2
+20
+2
+2
+3
+2
+2
+9
+2
+17
+2
+2
+3
+11
+3
+11
+2
+2
+2
+2
+2
+2
+4
+2
+3
+2
+2
+11
+3
+2
+4
+22
+2
+2
+3
+4
+11
+2
+2
+16
+17
+18
+7
+6
+3
+2
+3
+2
+3
+2
+2
+3
+25
+2
+3
+10
+2
+12
+2
+7
+12
+3
+2
+5
+2
+5
+2
+2
+10
+2
+2
+17
+3
+2
+5
+10
+16
+3
+2
+12
+2
+2
+2
+19
+3
+2
+18
+11
+6
+2
+2
+2
+2
+3
+2
+3
+2
+2
+2
+2
+2
+13
+2
+2
+2
+3
+2
+2
+2
+2
+15
+2
+3
+2
+2
+4
+8
+20
+2
+3
+4
+3
+17
+2
+13
+12
+5
+2
+2
+2
+2
+2
+3
+7
+13
+11
+2
+4
+10
+2
+2
+2
+3
+2
+24
+3
+2
+2
+7
+2
+3
+2
+2
+2
+2
+13
+2
+5
+3
+3
+2
+3
+2
+2
+9
+2
+2
+3
+13
+2
+2
+29
+20
+26
+3
+17
+2
+2
+13
+2
+7
+2
+2
+2
+2
+2
+3
+43
+2
+2
+26
+5
+3
+2
+14
+2
+2
+2
+16
+3
+2
+2
+12
+2
+2
+17
+2
+2
+2
+7
+2
+2
+6
+23
+3
+2
+2
+2
+3
+2
+2
+3
+7
+7
+2
+2
+3
+2
+22
+2
+2
+2
+11
+9
+8
+3
+2
+9
+2
+3
+2
+3
+2
+2
+3
+12
+2
+2
+2
+3
+13
+2
+2
+2
+2
+2
+17
+2
+2
+2
+26
+2
+2
+3
+2
+17
+2
+2
+2
+12
+3
+3
+4
+2
+3
+12
+12
+16
+6
+2
+3
+18
+2
+5
+2
+3
+6
+3
+3
+13
+3
+2
+14
+2
+2
+2
+4
+3
+2
+2
+2
+15
+19
+2
+2
+3
+37
+3
+2
+2
+2
+17
+10
+2
+8
+-1
+2
+16
+2
+10
+2
+39
+-1
+2
+2
+2
+2
+2
+10
+2
+2
+2
+12
+27
+18
+2
+2
+2
+8
+2
+2
+9
+2
+2
+4
+9
+14
+2
+2
+2
+9
+2
+2
+2
+2
+3
+2
+2
+2
+15
+13
+3
+2
+4
+2
+2
+10
+3
+2
+15
+2
+17
+2
+2
+2
+2
+3
+10
+2
+2
+4
+2
+2
+2
+6
+2
+2
+2
+3
+3
+-1
+2
+2
+-1
+2
+3
+5
+2
+9
+14
+9
+2
+11
+3
+3
+2
+2
+8
+9
+2
+2
+2
+2
+2
+2
+2
+2
+10
+19
+17
+3
+2
+2
+3
+2
+2
+2
+2
+10
+3
+2
+2
+3
+3
+10
+2
+19
+2
+3
+2
+2
+2
+2
+2
+9
+10
+2
+2
+3
+2
+2
+2
+-1
+2
+2
+3
+2
+2
+2
+10
+8
+15
+12
+2
+2
+11
+15
+2
+2
+2
+3
+3
+3
+2
+2
+15
+2
+3
+3
+3
+2
+2
+3
+11
+8
+2
+9
+2
+2
+15
+2
+3
+2
+2
+2
+2
+12
+2
+3
+-1
+17
+9
+3
+2
+2
+2
+2
+4
+2
+2
+2
+10
+7
+13
+2
+2
+13
+2
+9
+2
+2
+26
+2
+5
+3
+2
+2
+8
+2
+3
+2
+3
+3
+9
+10
+3
+13
+2
+3
+2
+2
+3
+15
+2
+2
+15
+2
+2
+16
+15
+3
+2
+2
+3
+7
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+28
+2
+2
+2
+2
+2
+28
+2
+2
+2
+8
+7
+3
+2
+9
+3
+2
+44
+16
+2
+2
+2
+2
+4
+2
+2
+2
+9
+33
+2
+2
+2
+3
+2
+2
+2
+2
+2
+12
+2
+2
+10
+2
+2
+2
+3
+2
+2
+3
+13
+4
+2
+19
+2
+13
+2
+3
+2
+6
+11
+15
+2
+2
+6
+2
+23
+5
+2
+2
+3
+17
+9
+2
+2
+2
+13
+13
+2
+2
+2
+3
+3
+2
+8
+2
+3
+16
+2
+2
+11
+2
+7
+2
+10
+6
+3
+2
+2
+2
+2
+2
+14
+2
+3
+4
+14
+2
+2
+3
+4
+8
+2
+2
+4
+3
+3
+18
+10
+14
+11
+5
+2
+3
+2
+18
+3
+12
+3
+2
+2
+9
+10
+2
+2
+12
+2
+2
+2
+2
+3
+2
+3
+2
+4
+2
+5
+2
+2
+3
+3
+2
+28
+2
+2
+3
+3
+2
+2
+27
+2
+2
+17
+2
+3
+2
+15
+13
+3
+3
+2
+9
+2
+2
+2
+2
+2
+8
+16
+12
+17
+4
+4
+2
+2
+11
+2
+3
+3
+2
+2
+3
+2
+2
+2
+2
+2
+2
+9
+2
+11
+2
+2
+9
+2
+2
+3
+14
+2
+13
+2
+9
+3
+2
+2
+2
+2
+2
+13
+2
+2
+2
+2
+2
+6
+3
+2
+2
+3
+2
+6
+2
+8
+10
+3
+2
+5
+3
+2
+3
+2
+2
+2
+6
+8
+2
+2
+2
+2
+2
+2
+8
+2
+2
+20
+2
+20
+3
+2
+5
+2
+3
+2
+2
+2
+3
+2
+2
+2
+2
+5
+2
+2
+5
+3
+15
+2
+2
+13
+3
+12
+8
+12
+3
+2
+2
+2
+5
+2
+3
+2
+18
+16
+2
+2
+2
+3
+6
+12
+4
+2
+2
+2
+2
+17
+26
+2
+11
+22
+2
+2
+2
+22
+3
+2
+17
+10
+2
+2
+3
+3
+23
+2
+-1
+23
+8
+2
+2
+3
+11
+3
+5
+2
+13
+2
+3
+2
+2
+9
+3
+3
+2
+2
+2
+2
+3
+2
+2
+5
+2
+2
+2
+2
+16
+3
+2
+2
+2
+12
+2
+3
+15
+2
+10
+2
+2
+5
+2
+2
+2
+2
+2
+3
+3
+2
+3
+2
+2
+22
+3
+2
+3
+2
+2
+2
+18
+2
+2
+2
+11
+2
+2
+2
+3
+2
+9
+5
+13
+3
+2
+2
+3
+2
+14
+3
+2
+2
+16
+3
+6
+3
+3
+2
+2
+4
+-1
+13
+2
+15
+2
+2
+3
+2
+17
+15
+9
+9
+2
+2
+2
+9
+3
+2
+14
+42
+20
+15
+19
+6
+12
+2
+9
+2
+2
+3
+2
+2
+2
+2
+13
+3
+2
+2
+2
+2
+2
+2
+3
+17
+10
+15
+2
+3
+20
+2
+2
+13
+3
+3
+2
+2
+3
+3
+3
+2
+2
+3
+2
+2
+3
+2
+13
+2
+2
+2
+15
+12
+17
+3
+3
+2
+3
+2
+3
+13
+10
+5
+3
+3
+21
+2
+2
+2
+2
+2
+32
+19
+3
+2
+2
+2
+3
+2
+2
+5
+4
+2
+2
+2
+6
+3
+3
+2
+2
+3
+2
+2
+3
+2
+5
+3
+3
+2
+2
+9
+3
+17
+13
+3
+3
+2
+2
+7
+2
+2
+14
+15
+2
+2
+2
+3
+5
+2
+2
+2
+2
+2
+11
+2
+21
+2
+9
+8
+2
+2
+2
+2
+2
+30
+3
+2
+18
+3
+24
+3
+2
+9
+2
+2
+2
+3
+4
+3
+9
+2
+3
+2
+2
+11
+2
+9
+12
+8
+13
+4
+3
+2
+2
+2
+15
+20
+27
+3
+11
+13
+10
+2
+2
+11
+3
+3
+2
+19
+2
+8
+4
+3
+15
+7
+3
+4
+2
+3
+13
+2
+3
+2
+3
+9
+2
+13
+2
+2
+16
+17
+12
+4
+3
+2
+2
+3
+3
+3
+10
+11
+4
+2
+11
+11
+2
+7
+2
+2
+4
+2
+2
+2
+7
+2
+7
+2
+2
+3
+16
+2
+12
+2
+22
+2
+3
+3
+2
+3
+6
+2
+2
+2
+3
+14
+25
+2
+25
+4
+15
+3
+2
+19
+2
+10
+12
+2
+2
+2
+2
+3
+2
+9
+2
+5
+13
+10
+2
+14
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+12
+2
+2
+2
+13
+3
+3
+3
+2
+6
+2
+2
+3
+3
+3
+2
+2
+15
+14
+10
+2
+2
+2
+2
+2
+5
+2
+8
+3
+3
+2
+3
+10
+3
+3
+11
+2
+2
+2
+2
+2
+12
+2
+2
+3
+18
+2
+2
+12
+3
+2
+2
+9
+8
+2
+2
+2
+2
+14
+3
+3
+2
+12
+2
+2
+14
+8
+7
+16
+2
+8
+2
+2
+3
+2
+14
+3
+2
+3
+3
+3
+2
+2
+2
+9
+20
+2
+10
+3
+17
+12
+2
+3
+15
+3
+2
+16
+2
+3
+8
+2
+2
+4
+15
+2
+3
+2
+3
+2
+2
+2
+15
+2
+12
+2
+3
+12
+2
+3
+3
+2
+13
+2
+2
+2
+2
+2
+7
+11
+2
+8
+12
+2
+3
+2
+2
+2
+21
+2
+3
+2
+2
+7
+2
+2
+-1
+2
+2
+3
+2
+2
+2
+2
+11
+3
+11
+3
+25
+10
+8
+2
+3
+5
+2
+2
+14
+3
+2
+11
+8
+8
+5
+2
+2
+7
+2
+2
+2
+17
+2
+4
+2
+3
+2
+11
+8
+2
+3
+2
+26
+11
+2
+20
+2
+3
+17
+11
+2
+8
+3
+2
+10
+6
+17
+16
+3
+2
+2
+17
+2
+3
+2
+3
+2
+2
+2
+3
+2
+5
+2
+2
+2
+10
+2
+2
+3
+3
+2
+16
+9
+3
+2
+12
+11
+2
+10
+2
+22
+2
+3
+3
+14
+2
+2
+12
+-1
+13
+2
+2
+2
+19
+2
+14
+21
+3
+15
+2
+6
+3
+2
+2
+2
+9
+-1
+5
+2
+2
+2
+3
+2
+8
+2
+2
+2
+4
+2
+2
+13
+8
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+20
+9
+4
+3
+14
+2
+2
+5
+2
+2
+3
+13
+3
+2
+9
+2
+16
+20
+2
+3
+2
+2
+3
+2
+3
+2
+2
+3
+-1
+2
+2
+20
+10
+12
+2
+23
+3
+2
+3
+2
+5
+29
+2
+17
+2
+2
+2
+20
+23
+8
+2
+2
+10
+6
+2
+2
+16
+17
+7
+2
+14
+32
+3
+3
+2
+11
+7
+2
+18
+2
+7
+16
+8
+2
+3
+2
+2
+2
+7
+9
+3
+8
+2
+13
+2
+23
+3
+2
+8
+3
+3
+6
+2
+2
+2
+4
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+13
+2
+26
+5
+3
+2
+3
+2
+2
+3
+2
+3
+8
+2
+16
+18
+2
+2
+2
+21
+2
+3
+2
+3
+2
+2
+12
+3
+2
+17
+3
+2
+3
+3
+2
+13
+2
+2
+3
+3
+3
+2
+2
+16
+2
+10
+3
+2
+2
+19
+4
+3
+3
+26
+2
+21
+2
+2
+2
+2
+3
+2
+2
+2
+3
+3
+2
+3
+14
+4
+3
+8
+4
+2
+3
+2
+2
+2
+2
+2
+2
+2
+3
+2
+2
+3
+2
+7
+2
+16
+2
+2
+2
+2
+2
+2
+3
+2
+3
+19
+2
+3
+2
+3
+2
+3
+2
+-1
+3
+3
+3
+10
+2
+2
+2
+3
+5
+2
+5
+13
+2
+3
+3
+21
+5
+3
+2
+2
+3
+6
+3
+2
+10
+2
+9
+2
+2
+2
+14
+33
+6
+9
+2
+3
+18
+3
+2
+2
+10
+2
+2
+2
+3
+2
+11
+12
+12
+3
+10
+2
+2
+4
+3
+29
+28
+2
+11
+3
+17
+2
+2
+18
+11
+2
+2
+2
+14
+2
+15
+2
+8
+7
+20
+2
+3
+3
+2
+3
+11
+2
+3
+3
+13
+2
+7
+2
+2
+3
+2
+9
+11
+2
+2
+2
+3
+2
+5
+3
+2
+2
+2
+2
+2
+3
+2
+2
+14
+3
+2
+3
+2
+2
+2
+2
+9
+24
+2
+3
+2
+12
+2
+2
+2
+3
+14
+2
+2
+6
+2
+2
+13
+3
+3
+2
+2
+2
+12
+10
+7
+13
+2
+2
+2
+32
+6
+10
+9
+2
+2
+2
+9
+9
+2
+5
+23
+29
+11
+2
+2
+29
+2
+15
+2
+10
+2
+2
+4
+2
+3
+4
+3
+2
+8
+-1
+2
+2
+13
+2
+2
+2
+2
+2
+2
+3
+2
+14
+2
+2
+9
+2
+6
+2
+2
+12
+4
+2
+2
+2
+13
+4
+3
+6
+12
+2
+3
+2
+2
+9
+2
+3
+3
+2
+16
+10
+2
+15
+2
+2
+7
+2
+3
+2
+2
+2
+11
+2
+2
+2
+24
+13
+28
+3
+2
+2
+3
+8
+2
+2
+5
+9
+2
+2
+3
+2
+2
+2
+2
+3
+-1
+2
+16
+2
+11
+3
+2
+3
+3
+2
+3
+2
+18
+2
+2
+2
+9
+2
+2
+2
+5
+8
+17
+22
+2
+3
+3
+3
+2
+2
+2
+13
+2
+2
+3
+15
+10
+2
+11
+2
+2
+2
+2
+3
+2
+11
+19
+3
+2
+2
+2
+11
+2
+20
+22
+2
+3
+14
+3
+3
+15
+2
+2
+7
+3
+3
+2
+2
+3
+2
+2
+3
+7
+2
+2
+11
+2
+3
+15
+2
+2
+2
+3
+2
+20
+2
+2
+13
+11
+7
+12
+2
+13
+47
+2
+7
+2
+3
+2
+2
+9
+10
+3
+3
+2
+8
+7
+2
+2
+5
+2
+3
+2
+12
+13
+2
+13
+2
+2
+6
+2
+13
+3
+2
+2
+4
+12
+2
+2
+2
+2
+2
+14
+2
+2
+3
+11
+7
+3
+3
+7
+3
+3
+10
+2
+19
+2
+2
+4
+2
+2
+2
+28
+2
+2
+3
+3
+2
+2
+-1
+2
+2
+2
+5
+2
+2
+12
+2
+2
+3
+3
+2
+-1
+3
+3
+2
+2
+3
+2
+2
+2
+5
+3
+13
+3
+9
+3
+3
+3
+2
+2
+2
+7
+2
+4
+2
+2
+9
+9
+2
+7
+2
+11
+2
+3
+2
+3
+2
+2
+8
+2
+-1
+2
+4
+2
+3
+19
+3
+2
+2
+3
+2
+4
+3
+3
+3
+2
+2
+10
+2
+2
+9
+2
+10
+2
+2
+14
+2
+2
+2
+2
+3
+2
+4
+2
+2
+14
+2
+3
+2
+11
+11
+2
+5
+14
+2
+2
+2
+5
+10
+3
+8
+4
+5
+18
+2
+15
+2
+10
+2
+2
+2
+3
+2
+16
+2
+2
+3
+15
+2
+2
+2
+2
+5
+2
+5
+2
+3
+3
+15
+2
+2
+2
+2
+7
+2
+2
+2
+8
+2
+2
+5
+2
+20
+2
+2
+10
+2
+15
+7
+2
+3
+2
+3
+4
+2
+10
+3
+8
+2
+2
+11
+2
+6
+2
+2
+2
+2
+3
+2
+11
+2
+2
+2
+2
+2
+9
+13
+2
+3
+2
+2
+2
+3
+3
+2
+3
+11
+2
+2
+12
+11
+2
+19
+3
+4
+5
+2
+12
+3
+2
+40
+3
+2
+2
+2
+2
+2
+9
+2
+2
+2
+-1
+2
+2
+15
+2
+2
+14
+14
+2
+2
+2
+5
+8
+3
+4
+2
+2
+2
+2
+3
+3
+2
+2
+3
+11
+9
+3
+2
+2
+3
+3
+2
+2
+2
+13
+2
+2
+9
+19
+2
+2
+2
+13
+2
+14
+3
+2
+2
+2
+3
+2
+2
+2
+2
+14
+2
+2
+2
+2
+2
+2
+5
+3
+2
+2
+2
+2
+2
+2
+2
+17
+2
+3
+14
+2
+2
+3
+-1
+10
+18
+5
+2
+2
+2
+2
+3
+2
+2
+3
+2
+2
+2
+2
+2
+13
+2
+5
+2
+5
+2
+2
+2
+2
+6
+2
+19
+2
+2
+2
+2
+2
+3
+11
+3
+2
+2
+3
+2
+5
+2
+2
+19
+2
+6
+5
+5
+12
+2
+10
+9
+11
+2
+8
+15
+7
+2
+2
+2
+2
+2
+2
+2
+17
+15
+2
+17
+3
+3
+12
+2
+2
+10
+10
+3
+2
+2
+2
+2
+7
+2
+2
+9
+10
+3
+3
+2
+2
+2
+3
+2
+9
+2
+4
+17
+12
+2
+2
+2
+2
+7
+3
+2
+2
+3
+2
+2
+2
+9
+2
+2
+4
+15
+2
+2
+2
+2
+16
+16
+7
+4
+2
+13
+2
+2
+3
+2
+2
+4
+19
+2
+2
+6
+2
+2
+2
+2
+2
+3
+23
+2
+8
+17
+2
+7
+6
+2
+3
+18
+2
+2
+2
+3
+2
+3
+2
+15
+2
+2
+2
+2
+4
+2
+5
+3
+2
+15
+21
+5
+2
+15
+3
+2
+2
+4
+2
+2
+15
+3
+2
+3
+9
+2
+3
+6
+2
+6
+3
+2
+-1
+2
+3
+2
+2
+2
+18
+2
+2
+12
+3
+2
+2
+6
+2
+10
+2
+13
+48
+2
+2
+12
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+11
+2
+2
+12
+6
+2
+2
+4
+2
+9
+5
+10
+2
+2
+2
+12
+2
+3
+24
+3
+12
+2
+2
+18
+3
+3
+3
+2
+2
+4
+2
+3
+2
+9
+21
+8
+9
+2
+7
+2
+8
+2
+3
+16
+13
+2
+9
+7
+2
+2
+17
+2
+2
+3
+2
+2
+3
+2
+2
+2
+2
+2
+2
+19
+16
+2
+6
+7
+12
+3
+3
+2
+3
+15
+2
+14
+2
+5
+10
+7
+7
+14
+2
+2
+2
+3
+3
+2
+9
+3
+13
+2
+3
+2
+3
+2
+15
+2
+2
+2
+2
+7
+2
+2
+20
+3
+2
+13
+2
+2
+2
+2
+2
+2
+2
+2
+10
+2
+3
+2
+3
+28
+2
+2
+3
+2
+7
+2
+3
+2
+2
+20
+2
+2
+2
+2
+2
+2
+3
+2
+2
+3
+3
+15
+2
+2
+2
+2
+19
+3
+3
+11
+2
+2
+2
+3
+5
+2
+2
+16
+2
+2
+2
+2
+3
+2
+9
+24
+12
+3
+3
+16
+2
+2
+7
+2
+7
+2
+2
+2
+2
+2
+2
+4
+2
+2
+2
+2
+2
+17
+2
+2
+11
+14
+3
+2
+3
+3
+3
+3
+2
+2
+11
+3
+15
+4
+3
+2
+2
+18
+8
+2
+17
+2
+11
+3
+2
+2
+2
+2
+2
+25
+2
+2
+15
+2
+2
+2
+2
+2
+15
+3
+2
+11
+2
+2
+2
+3
+4
+2
+2
+15
+2
+11
+2
+15
+2
+2
+2
+2
+3
+2
+3
+2
+2
+5
+11
+2
+2
+2
+9
+16
+10
+3
+2
+22
+18
+3
+2
+5
+3
+2
+2
+4
+2
+13
+2
+3
+2
+2
+2
+2
+10
+2
+3
+2
+2
+2
+2
+10
+3
+2
+2
+3
+20
+3
+3
+21
+13
+2
+3
+2
+2
+10
+7
+2
+2
+2
+5
+2
+2
+14
+2
+9
+2
+2
+16
+3
+3
+2
+3
+2
+2
+5
+2
+2
+2
+2
+3
+11
+3
+2
+10
+13
+14
+2
+2
+2
+3
+2
+15
+3
+2
+3
+2
+2
+3
+18
+2
+2
+12
+13
+12
+10
+2
+3
+2
+5
+3
+9
+2
+3
+3
+3
+2
+2
+2
+2
+11
+2
+2
+2
+10
+2
+2
+12
+13
+2
+2
+31
+6
+16
+2
+2
+2
+2
+2
+14
+11
+2
+2
+24
+4
+12
+2
+2
+2
+2
+13
+2
+2
+2
+2
+20
+2
+19
+8
+6
+2
+17
+2
+2
+2
+3
+4
+2
+2
+2
+2
+2
+2
+2
+3
+2
+32
+2
+2
+3
+13
+3
+2
+2
+2
+3
+2
+3
+2
+2
+2
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+9
+2
+8
+2
+5
+2
+9
+2
+2
+2
+4
+2
+2
+23
+2
+14
+2
+2
+2
+2
+2
+2
+2
+3
+9
+16
+16
+2
+2
+3
+14
+2
+10
+15
+2
+2
+2
+2
+3
+2
+17
+2
+3
+2
+2
+2
+2
+2
+6
+48
+12
+2
+2
+2
+3
+2
+9
+2
+2
+3
+2
+7
+3
+2
+2
+10
+12
+3
+2
+2
+2
+2
+5
+15
+18
+2
+2
+12
+3
+17
+2
+7
+3
+19
+3
+3
+6
+3
+2
+2
+3
+2
+2
+22
+3
+2
+7
+2
+2
+13
+16
+18
+2
+2
+7
+9
+4
+2
+2
+11
+2
+3
+2
+4
+3
+3
+2
+2
+2
+10
+3
+3
+3
+25
+3
+3
+2
+2
+3
+2
+2
+13
+3
+18
+2
+5
+2
+2
+4
+3
+9
+2
+11
+10
+2
+18
+3
+2
+3
+2
+9
+2
+15
+2
+2
+3
+2
+2
+2
+2
+2
+17
+9
+4
+10
+2
+3
+16
+2
+2
+2
+13
+2
+2
+4
+22
+2
+23
+2
+2
+26
+3
+2
+8
+2
+12
+2
+3
+2
+15
+3
+2
+2
+12
+2
+2
+2
+2
+2
+2
+2
+2
+3
+2
+3
+2
+2
+2
+19
+15
+2
+3
+2
+20
+2
+3
+3
+2
+3
+7
+36
+2
+2
+2
+2
+16
+4
+2
+3
+2
+2
+2
+2
+2
+2
+3
+3
+13
+3
+2
+4
+2
+2
+2
+22
+2
+2
+2
+3
+3
+2
+3
+2
+2
+2
+2
+2
+2
+15
+2
+2
+2
+18
+21
+9
+2
+2
+2
+2
+6
+15
+2
+2
+2
+6
+2
+2
+4
+9
+3
+9
+2
+2
+3
+2
+2
+19
+2
+2
+2
+2
+2
+2
+6
+2
+2
+9
+2
+2
+2
+2
+2
+2
+23
+2
+8
+2
+3
+12
+2
+2
+3
+3
+2
+2
+15
+2
+2
+15
+7
+2
+3
+2
+2
+2
+5
+9
+2
+2
+3
+2
+4
+2
+2
+3
+2
+2
+9
+7
+2
+2
+19
+9
+-1
+3
+3
+20
+2
+3
+2
+2
+3
+5
+3
+9
+2
+3
+6
+14
+2
+2
+2
+6
+2
+2
+2
+20
+15
+7
+2
+10
+13
+17
+3
+3
+2
+2
+32
+2
+2
+25
+2
+2
+3
+2
+20
+3
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+20
+2
+10
+10
+2
+3
+2
+2
+2
+2
+4
+6
+2
+2
+3
+2
+2
+2
+31
+2
+2
+3
+2
+2
+2
+6
+2
+5
+2
+6
+2
+2
+5
+3
+3
+2
+2
+2
+2
+3
+2
+2
+2
+11
+10
+3
+18
+6
+2
+4
+30
+2
+9
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+3
+9
+2
+3
+2
+2
+10
+8
+15
+9
+2
+14
+3
+2
+6
+10
+2
+2
+2
+20
+2
+2
+3
+2
+2
+13
+2
+2
+3
+2
+24
+2
+3
+15
+2
+3
+3
+3
+2
+2
+8
+9
+2
+2
+2
+15
+2
+3
+3
+2
+2
+2
+3
+2
+2
+2
+2
+2
+3
+2
+2
+2
+9
+2
+3
+2
+2
+2
+2
+2
+3
+3
+2
+21
+2
+3
+11
+24
+3
+2
+2
+3
+2
+3
+2
+2
+2
+2
+2
+2
+2
+2
+8
+12
+2
+14
+2
+9
+4
+3
+2
+25
+14
+2
+2
+8
+2
+3
+6
+2
+12
+2
+8
+2
+2
+5
+2
+2
+14
+2
+9
+2
+11
+5
+2
+13
+8
+2
+3
+2
+2
+22
+2
+10
+2
+3
+2
+2
+19
+2
+3
+2
+2
+2
+3
+11
+9
+2
+3
+3
+8
+2
+15
+15
+3
+2
+2
+2
+36
+3
+2
+2
+2
+2
+11
+6
+2
+2
+2
+2
+2
+3
+2
+2
+18
+2
+2
+2
+3
+2
+2
+2
+3
+32
+3
+2
+2
+2
+3
+2
+13
+2
+2
+3
+15
+4
+2
+16
+2
+2
+3
+2
+8
+2
+3
+2
+2
+3
+2
+4
+2
+4
+2
+23
+6
+3
+4
+2
+2
+2
+2
+2
+9
+2
+9
+5
+2
+8
+2
+2
+2
+6
+2
+5
+2
+3
+2
+2
+2
+9
+2
+2
+2
+2
+3
+2
+2
+3
+2
+2
+3
+2
+12
+11
+2
+2
+19
+3
+8
+2
+2
+2
+3
+2
+16
+2
+11
+2
+2
+9
+2
+9
+2
+3
+2
+2
+2
+3
+5
+2
+2
+5
+2
+2
+2
+16
+2
+3
+2
+13
+2
+2
+2
+2
+11
+2
+2
+2
+19
+8
+7
+9
+3
+2
+2
+17
+2
+3
+2
+4
+2
+3
+2
+12
+2
+2
+16
+2
+2
+3
+2
+2
+14
+20
+4
+5
+18
+3
+9
+2
+2
+5
+2
+2
+2
+4
+2
+10
+10
+2
+2
+11
+2
+2
+3
+14
+2
+13
+14
+2
+3
+5
+3
+2
+2
+2
+11
+2
+4
+2
+3
+2
+3
+18
+5
+2
+2
+3
+3
+10
+18
+2
+2
+2
+2
+8
+12
+2
+5
+2
+2
+3
+2
+2
+13
+2
+2
+3
+2
+19
+2
+2
+21
+12
+7
+2
+3
+2
+12
+2
+3
+2
+9
+7
+2
+2
+3
+2
+2
+7
+2
+26
+30
+14
+3
+3
+10
+3
+3
+9
+7
+2
+2
+12
+8
+3
+2
+2
+3
+2
+5
+14
+13
+2
+3
+13
+9
+8
+2
+24
+2
+3
+7
+15
+19
+18
+3
+15
+2
+2
+2
+2
+9
+2
+2
+14
+2
+2
+2
+2
+2
+2
+2
+16
+2
+2
+4
+2
+2
+17
+2
+2
+13
+9
+2
+2
+2
+2
+3
+2
+3
+8
+2
+3
+2
+17
+2
+3
+2
+2
+3
+2
+2
+2
+2
+2
+2
+3
+9
+8
+3
+2
+10
+3
+2
+12
+2
+2
+2
+18
+4
+2
+13
+3
+2
+3
+2
+16
+9
+2
+2
+3
+3
+5
+2
+2
+5
+5
+13
+2
+2
+9
+10
+2
+3
+2
+2
+2
+17
+2
+3
+10
+8
+2
+3
+2
+14
+2
+3
+7
+2
+2
+14
+2
+3
+3
+11
+2
+2
+2
+7
+7
+3
+2
+2
+2
+2
+3
+2
+3
+2
+4
+14
+6
+3
+3
+2
+2
+-1
+2
+21
+17
+3
+25
+2
+6
+2
+2
+2
+2
+2
+2
+2
+3
+3
+2
+2
+12
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_1.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_1.txt
new file mode 100644
index 0000000..24b000b
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_1.txt
@@ -0,0 +1,100 @@
+54
+72
+124
+175
+70
+267
+295
+396
+365
+132
+312
+381
+252
+359
+210
+489
+160
+185
+177
+-1
+-1
+443
+-1
+255
+147
+141
+-1
+121
+-1
+119
+-1
+139
+140
+-1
+-1
+122
+535
+258
+36
+-1
+-1
+171
+523
+161
+-1
+534
+204
+-1
+197
+-1
+326
+54
+111
+72
+90
+-1
+187
+-1
+243
+174
+484
+136
+-1
+176
+590
+583
+204
+171
+227
+143
+110
+242
+165
+240
+585
+152
+251
+449
+343
+234
+67
+289
+322
+161
+-1
+502
+77
+98
+39
+503
+175
+358
+-1
+43
+56
+206
+368
+-1
+324
+352
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_10.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_10.txt
new file mode 100644
index 0000000..ea6d8b1
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_10.txt
@@ -0,0 +1,100 @@
+57
+113
+121
+142
+178
+62
+190
+275
+149
+185
+205
+500
+391
+242
+21
+148
+105
+-1
+189
+23
+-1
+-1
+78
+175
+189
+152
+438
+236
+84
+424
+56
+14
+223
+130
+-1
+108
+-1
+123
+63
+118
+118
+-1
+320
+336
+34
+35
+112
+75
+-1
+32
+34
+45
+43
+21
+29
+165
+40
+463
+160
+273
+440
+95
+293
+165
+472
+243
+52
+219
+120
+36
+81
+49
+64
+150
+-1
+107
+59
+45
+252
+-1
+-1
+70
+-1
+116
+80
+113
+118
+78
+81
+46
+205
+121
+303
+109
+355
+65
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_11.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_11.txt
new file mode 100644
index 0000000..6785cc9
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_11.txt
@@ -0,0 +1,100 @@
+36
+33
+99
+73
+187
+182
+62
+303
+89
+228
+199
+75
+61
+83
+84
+179
+308
+78
+-1
+161
+147
+103
+16
+34
+37
+115
+65
+148
+19
+95
+136
+187
+76
+122
+154
+40
+135
+125
+22
+-1
+152
+146
+222
+64
+49
+28
+36
+54
+343
+-1
+83
+41
+86
+114
+340
+163
+-1
+56
+185
+22
+142
+84
+593
+343
+92
+278
+71
+74
+131
+17
+38
+251
+-1
+353
+72
+227
+70
+83
+45
+234
+50
+225
+120
+38
+41
+293
+326
+515
+-1
+64
+300
+81
+123
+273
+21
+306
+-1
+142
+-1
+320
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_12.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_12.txt
new file mode 100644
index 0000000..e459ee8
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_12.txt
@@ -0,0 +1,100 @@
+16
+48
+29
+14
+191
+199
+29
+257
+341
+527
+345
+374
+87
+39
+-1
+257
+151
+-1
+-1
+63
+16
+22
+124
+257
+128
+-1
+201
+102
+114
+184
+30
+116
+47
+202
+214
+266
+224
+95
+31
+21
+97
+87
+203
+238
+141
+49
+-1
+60
+139
+25
+238
+18
+338
+185
+141
+272
+250
+184
+30
+153
+127
+98
+368
+23
+83
+44
+-1
+65
+-1
+15
+39
+238
+122
+46
+272
+23
+320
+32
+36
+73
+191
+199
+351
+223
+-1
+181
+109
+-1
+71
+91
+36
+139
+556
+69
+163
+216
+116
+-1
+538
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_13.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_13.txt
new file mode 100644
index 0000000..23f92ce
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_13.txt
@@ -0,0 +1,100 @@
+40
+62
+29
+83
+118
+85
+30
+110
+196
+299
+98
+50
+205
+328
+23
+21
+63
+238
+174
+546
+110
+84
+31
+235
+120
+146
+118
+20
+24
+61
+151
+56
+-1
+73
+133
+-1
+159
+45
+67
+283
+43
+-1
+38
+37
+17
+49
+-1
+96
+127
+55
+-1
+108
+489
+350
+138
+94
+172
+36
+167
+211
+15
+314
+242
+136
+140
+20
+-1
+317
+250
+241
+189
+-1
+454
+27
+596
+193
+215
+57
+137
+256
+184
+30
+186
+61
+37
+129
+145
+20
+165
+94
+226
+-1
+44
+128
+65
+-1
+78
+75
+386
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_14.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_14.txt
new file mode 100644
index 0000000..c115a6f
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_14.txt
@@ -0,0 +1,100 @@
+20
+30
+24
+50
+111
+32
+94
+15
+45
+248
+21
+140
+213
+291
+62
+39
+71
+119
+196
+59
+-1
+60
+50
+311
+52
+191
+-1
+-1
+80
+69
+-1
+-1
+26
+65
+127
+61
+163
+99
+197
+204
+-1
+163
+117
+98
+26
+37
+259
+95
+58
+278
+41
+23
+466
+71
+52
+23
+173
+175
+105
+28
+177
+-1
+75
+49
+41
+36
+183
+541
+192
+585
+23
+84
+105
+-1
+121
+210
+32
+32
+-1
+39
+33
+58
+80
+73
+174
+497
+263
+250
+78
+268
+97
+29
+180
+-1
+96
+115
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_15.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_15.txt
new file mode 100644
index 0000000..2f845cf
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_15.txt
@@ -0,0 +1,100 @@
+14
+16
+102
+-1
+-1
+60
+47
+-1
+-1
+-1
+89
+-1
+197
+256
+198
+280
+213
+283
+113
+280
+395
+-1
+-1
+357
+-1
+-1
+-1
+-1
+224
+-1
+257
+134
+64
+-1
+-1
+112
+-1
+84
+283
+-1
+-1
+-1
+-1
+34
+385
+165
+-1
+236
+-1
+39
+-1
+56
+-1
+189
+-1
+74
+116
+-1
+-1
+62
+-1
+61
+-1
+-1
+-1
+-1
+-1
+-1
+75
+238
+263
+59
+-1
+16
+-1
+-1
+243
+16
+198
+-1
+-1
+-1
+-1
+62
+517
+-1
+-1
+172
+49
+40
+-1
+35
+225
+-1
+23
+112
+-1
+425
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_16.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_16.txt
new file mode 100644
index 0000000..f8eb369
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_16.txt
@@ -0,0 +1,100 @@
+147
+201
+149
+200
+-1
+18
+498
+-1
+-1
+222
+86
+239
+-1
+101
+47
+201
+-1
+-1
+17
+-1
+-1
+-1
+49
+-1
+251
+68
+141
+472
+-1
+287
+149
+-1
+125
+445
+164
+17
+-1
+-1
+58
+-1
+397
+496
+90
+53
+-1
+-1
+34
+597
+-1
+264
+405
+239
+-1
+-1
+-1
+-1
+17
+46
+73
+97
+285
+124
+65
+306
+479
+213
+-1
+320
+183
+36
+-1
+29
+99
+26
+198
+221
+434
+152
+-1
+-1
+-1
+-1
+-1
+203
+185
+61
+-1
+70
+132
+392
+334
+56
+368
+162
+471
+-1
+511
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_17.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_17.txt
new file mode 100644
index 0000000..4745351
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_17.txt
@@ -0,0 +1,100 @@
+170
+288
+-1
+-1
+-1
+69
+-1
+-1
+-1
+275
+95
+355
+267
+263
+174
+-1
+249
+-1
+80
+400
+15
+-1
+141
+115
+43
+-1
+233
+65
+-1
+45
+-1
+476
+194
+-1
+-1
+109
+286
+-1
+-1
+14
+-1
+66
+-1
+228
+78
+-1
+356
+162
+-1
+60
+141
+-1
+-1
+37
+-1
+-1
+-1
+422
+264
+-1
+-1
+476
+-1
+-1
+213
+112
+-1
+99
+310
+538
+-1
+-1
+-1
+-1
+-1
+51
+376
+-1
+203
+125
+189
+185
+340
+50
+64
+16
+-1
+-1
+250
+117
+-1
+155
+34
+16
+18
+-1
+360
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_18.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_18.txt
new file mode 100644
index 0000000..3470af0
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_18.txt
@@ -0,0 +1,100 @@
+14
+71
+223
+73
+323
+451
+77
+-1
+-1
+-1
+17
+80
+-1
+167
+326
+15
+198
+151
+-1
+191
+200
+100
+164
+-1
+125
+-1
+-1
+-1
+-1
+181
+437
+-1
+244
+108
+-1
+303
+-1
+268
+-1
+122
+223
+285
+343
+101
+-1
+143
+-1
+84
+124
+170
+62
+143
+-1
+-1
+224
+91
+-1
+-1
+-1
+86
+-1
+-1
+52
+193
+-1
+-1
+81
+95
+-1
+33
+-1
+404
+291
+-1
+-1
+340
+14
+-1
+-1
+-1
+-1
+-1
+31
+-1
+-1
+255
+141
+-1
+52
+-1
+-1
+16
+472
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_19.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_19.txt
new file mode 100644
index 0000000..aa51f21
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_19.txt
@@ -0,0 +1,100 @@
+160
+292
+57
+212
+67
+83
+37
+434
+165
+342
+157
+-1
+-1
+139
+-1
+230
+403
+-1
+290
+56
+-1
+220
+419
+-1
+119
+-1
+281
+216
+355
+137
+-1
+305
+-1
+79
+424
+-1
+-1
+260
+81
+135
+-1
+136
+16
+54
+76
+297
+114
+-1
+-1
+-1
+49
+235
+-1
+154
+76
+-1
+571
+90
+-1
+194
+96
+120
+-1
+-1
+-1
+96
+-1
+31
+-1
+111
+349
+204
+-1
+-1
+-1
+-1
+274
+102
+38
+495
+197
+278
+-1
+-1
+-1
+447
+67
+-1
+-1
+-1
+87
+-1
+-1
+493
+-1
+211
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_2.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_2.txt
new file mode 100644
index 0000000..5f72205
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_2.txt
@@ -0,0 +1,100 @@
+34
+148
+175
+29
+87
+40
+277
+323
+305
+245
+233
+172
+51
+299
+-1
+183
+422
+173
+376
+52
+370
+15
+113
+-1
+156
+-1
+28
+98
+311
+92
+360
+208
+45
+197
+350
+-1
+266
+-1
+148
+158
+104
+52
+562
+274
+93
+115
+-1
+500
+257
+16
+262
+-1
+128
+-1
+474
+98
+-1
+-1
+-1
+77
+232
+-1
+82
+36
+141
+134
+75
+25
+206
+81
+-1
+-1
+-1
+286
+-1
+121
+-1
+78
+265
+114
+87
+236
+101
+-1
+190
+139
+151
+-1
+125
+90
+270
+-1
+115
+218
+-1
+534
+242
+319
+489
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_20.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_20.txt
new file mode 100644
index 0000000..02eb352
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_20.txt
@@ -0,0 +1,100 @@
+137
+114
+207
+184
+226
+147
+127
+140
+317
+328
+-1
+-1
+-1
+184
+53
+520
+-1
+137
+-1
+262
+188
+-1
+187
+-1
+69
+161
+82
+-1
+458
+-1
+-1
+174
+231
+-1
+-1
+-1
+427
+-1
+-1
+182
+234
+-1
+83
+218
+-1
+271
+-1
+33
+-1
+-1
+42
+-1
+-1
+429
+406
+-1
+481
+279
+77
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+95
+112
+117
+-1
+488
+-1
+336
+-1
+-1
+152
+40
+-1
+-1
+41
+113
+-1
+-1
+318
+215
+-1
+-1
+75
+152
+15
+158
+163
+205
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_3.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_3.txt
new file mode 100644
index 0000000..10136b0
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_3.txt
@@ -0,0 +1,100 @@
+27
+25
+126
+83
+204
+127
+17
+239
+98
+103
+175
+446
+564
+39
+309
+238
+354
+126
+94
+83
+54
+165
+392
+156
+147
+241
+120
+111
+415
+71
+145
+203
+-1
+52
+195
+-1
+54
+148
+-1
+-1
+155
+16
+72
+383
+266
+216
+26
+422
+245
+61
+296
+45
+151
+164
+-1
+119
+254
+37
+141
+-1
+-1
+346
+154
+22
+69
+18
+96
+312
+105
+117
+-1
+120
+50
+51
+151
+240
+548
+-1
+161
+111
+-1
+-1
+130
+75
+95
+151
+-1
+225
+-1
+-1
+181
+38
+210
+566
+132
+110
+-1
+203
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_4.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_4.txt
new file mode 100644
index 0000000..7faf3a1
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_4.txt
@@ -0,0 +1,100 @@
+106
+131
+129
+146
+151
+49
+70
+264
+80
+37
+131
+88
+105
+211
+119
+71
+64
+76
+53
+134
+41
+50
+213
+259
+211
+533
+57
+235
+65
+210
+110
+227
+101
+187
+343
+140
+38
+168
+158
+48
+37
+77
+42
+483
+-1
+15
+59
+98
+548
+456
+79
+-1
+235
+-1
+155
+-1
+507
+94
+23
+112
+75
+24
+253
+239
+68
+310
+68
+88
+59
+34
+74
+114
+142
+42
+159
+245
+-1
+120
+62
+138
+16
+-1
+119
+439
+116
+96
+26
+-1
+96
+283
+122
+285
+37
+63
+118
+99
+265
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_5.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_5.txt
new file mode 100644
index 0000000..b2def9b
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_5.txt
@@ -0,0 +1,100 @@
+46
+58
+47
+135
+135
+201
+245
+405
+130
+200
+157
+-1
+-1
+86
+29
+264
+34
+-1
+44
+-1
+166
+-1
+73
+17
+368
+53
+-1
+37
+335
+18
+76
+195
+-1
+164
+300
+108
+74
+59
+216
+46
+56
+96
+46
+109
+71
+173
+314
+72
+-1
+184
+-1
+123
+410
+243
+-1
+78
+-1
+74
+166
+63
+55
+419
+349
+76
+125
+94
+112
+61
+339
+296
+287
+93
+492
+193
+134
+74
+90
+125
+118
+-1
+134
+62
+171
+101
+193
+446
+252
+517
+-1
+-1
+80
+73
+252
+88
+119
+188
+189
+313
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_6.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_6.txt
new file mode 100644
index 0000000..b443d90
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_6.txt
@@ -0,0 +1,100 @@
+17
+44
+87
+112
+89
+55
+167
+59
+101
+157
+28
+128
+93
+260
+67
+-1
+57
+53
+154
+-1
+81
+154
+-1
+-1
+212
+-1
+113
+108
+196
+268
+149
+422
+45
+103
+-1
+130
+-1
+312
+234
+81
+-1
+76
+51
+62
+342
+258
+78
+40
+250
+-1
+88
+-1
+124
+109
+188
+80
+244
+423
+364
+179
+57
+-1
+29
+78
+124
+50
+165
+246
+-1
+120
+-1
+108
+44
+193
+-1
+22
+118
+95
+217
+27
+37
+127
+60
+276
+66
+124
+132
+61
+101
+111
+78
+163
+49
+207
+55
+17
+188
+117
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_7.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_7.txt
new file mode 100644
index 0000000..e3e739e
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_7.txt
@@ -0,0 +1,100 @@
+43
+102
+190
+168
+206
+227
+149
+295
+313
+184
+61
+-1
+372
+26
+178
+-1
+63
+-1
+225
+233
+63
+318
+203
+248
+179
+39
+95
+168
+590
+-1
+571
+562
+163
+218
+46
+323
+123
+563
+82
+20
+229
+208
+31
+442
+-1
+195
+-1
+191
+131
+301
+128
+100
+196
+-1
+42
+191
+71
+189
+50
+75
+28
+107
+340
+64
+27
+63
+50
+73
+183
+97
+57
+-1
+490
+36
+177
+464
+121
+101
+197
+285
+93
+48
+14
+494
+-1
+21
+84
+142
+109
+80
+117
+-1
+133
+112
+19
+110
+-1
+349
+-1
+363
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_8.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_8.txt
new file mode 100644
index 0000000..81b6962
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_8.txt
@@ -0,0 +1,100 @@
+40
+60
+98
+155
+130
+92
+33
+107
+175
+249
+248
+-1
+-1
+264
+137
+112
+84
+283
+-1
+50
+-1
+55
+240
+188
+-1
+91
+95
+88
+82
+177
+315
+66
+350
+-1
+-1
+-1
+182
+219
+75
+315
+24
+271
+570
+16
+-1
+457
+88
+157
+340
+160
+41
+480
+55
+-1
+195
+274
+135
+49
+523
+25
+469
+531
+497
+-1
+487
+25
+-1
+45
+39
+-1
+422
+169
+141
+269
+148
+159
+228
+85
+212
+213
+41
+126
+69
+205
+136
+34
+147
+315
+141
+-1
+102
+30
+205
+132
+177
+210
+171
+-1
+583
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_9.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_9.txt
new file mode 100644
index 0000000..4659bda
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_9.txt
@@ -0,0 +1,100 @@
+74
+77
+164
+132
+176
+180
+129
+76
+151
+173
+83
+83
+61
+159
+47
+219
+263
+98
+-1
+110
+-1
+158
+154
+119
+160
+54
+73
+49
+88
+100
+145
+28
+28
+-1
+-1
+132
+390
+172
+228
+37
+462
+17
+396
+15
+154
+151
+409
+176
+66
+212
+-1
+130
+-1
+90
+-1
+144
+411
+101
+-1
+187
+121
+74
+52
+388
+65
+54
+164
+32
+151
+205
+17
+95
+87
+276
+71
+126
+37
+54
+139
+171
+-1
+129
+25
+16
+60
+175
+-1
+97
+-1
+-1
+65
+15
+164
+-1
+-1
+-1
+83
+-1
+445
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_1.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_1.txt
new file mode 100644
index 0000000..98e43f5
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_1.txt
@@ -0,0 +1,100 @@
+84
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+20
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+25
+-1
+-1
+-1
+74
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+-1
+87
+-1
+-1
+-1
+-1
+61
+-1
+-1
+-1
+-1
+-1
+-1
+87
+-1
+-1
+-1
+-1
+91
+73
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+69
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+55
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+99
+92
+68
+-1
+-1
+-1
+17
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_10.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_10.txt
new file mode 100644
index 0000000..86fd461
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_10.txt
@@ -0,0 +1,100 @@
+20
+36
+60
+-1
+-1
+-1
+-1
+-1
+-1
+94
+34
+33
+-1
+23
+75
+57
+-1
+15
+-1
+-1
+44
+-1
+-1
+41
+22
+78
+-1
+58
+70
+-1
+-1
+22
+-1
+-1
+14
+-1
+-1
+-1
+-1
+33
+14
+26
+23
+-1
+-1
+-1
+92
+-1
+-1
+66
+-1
+-1
+-1
+-1
+61
+57
+47
+-1
+52
+-1
+-1
+97
+61
+-1
+-1
+-1
+-1
+90
+-1
+82
+-1
+-1
+-1
+68
+76
+85
+-1
+-1
+-1
+69
+-1
+-1
+-1
+-1
+18
+-1
+46
+-1
+28
+-1
+-1
+-1
+14
+-1
+-1
+76
+59
+-1
+39
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_11.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_11.txt
new file mode 100644
index 0000000..d0dbd9a
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_11.txt
@@ -0,0 +1,100 @@
+39
+59
+17
+60
+-1
+-1
+-1
+-1
+-1
+69
+33
+26
+-1
+45
+-1
+70
+73
+62
+-1
+99
+-1
+-1
+-1
+53
+-1
+75
+64
+14
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+64
+-1
+-1
+-1
+21
+-1
+-1
+30
+96
+-1
+-1
+-1
+14
+14
+49
+88
+-1
+-1
+-1
+-1
+40
+-1
+-1
+-1
+-1
+39
+28
+-1
+-1
+-1
+40
+-1
+82
+-1
+-1
+-1
+-1
+-1
+-1
+77
+-1
+-1
+44
+-1
+-1
+62
+-1
+20
+92
+37
+-1
+-1
+-1
+63
+-1
+14
+-1
+38
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_12.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_12.txt
new file mode 100644
index 0000000..008c989
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_12.txt
@@ -0,0 +1,100 @@
+67
+70
+-1
+-1
+92
+-1
+-1
+-1
+53
+-1
+24
+63
+-1
+-1
+-1
+-1
+41
+-1
+78
+22
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+20
+22
+48
+-1
+-1
+-1
+92
+-1
+80
+53
+71
+18
+59
+-1
+-1
+84
+39
+-1
+32
+-1
+27
+91
+59
+30
+62
+-1
+80
+-1
+72
+-1
+-1
+73
+-1
+15
+30
+30
+-1
+-1
+-1
+-1
+44
+37
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+22
+51
+86
+40
+87
+-1
+-1
+-1
+-1
+-1
+-1
+31
+18
+-1
+59
+42
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_13.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_13.txt
new file mode 100644
index 0000000..1e39d98
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_13.txt
@@ -0,0 +1,100 @@
+21
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+37
+47
+-1
+51
+97
+-1
+-1
+64
+-1
+19
+98
+-1
+-1
+44
+-1
+-1
+-1
+-1
+86
+-1
+-1
+-1
+-1
+68
+69
+62
+-1
+-1
+36
+-1
+-1
+-1
+-1
+21
+-1
+-1
+-1
+-1
+-1
+48
+15
+-1
+-1
+91
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+53
+14
+-1
+-1
+-1
+-1
+57
+-1
+-1
+39
+-1
+36
+72
+-1
+47
+-1
+-1
+-1
+-1
+-1
+41
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_14.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_14.txt
new file mode 100644
index 0000000..a0b1090
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_14.txt
@@ -0,0 +1,100 @@
+38
+73
+67
+-1
+-1
+-1
+-1
+-1
+59
+-1
+88
+54
+-1
+-1
+70
+52
+-1
+-1
+-1
+-1
+43
+-1
+-1
+-1
+-1
+-1
+92
+-1
+-1
+-1
+64
+91
+-1
+-1
+-1
+-1
+68
+-1
+79
+54
+-1
+51
+-1
+63
+43
+-1
+93
+-1
+-1
+-1
+-1
+28
+-1
+44
+38
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+84
+-1
+38
+57
+-1
+-1
+-1
+45
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+65
+35
+-1
+76
+-1
+44
+-1
+-1
+33
+39
+-1
+54
+-1
+-1
+-1
+-1
+-1
+-1
+88
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_15.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_15.txt
new file mode 100644
index 0000000..f7c1a2d
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_15.txt
@@ -0,0 +1,100 @@
+14
+50
+69
+58
+-1
+34
+-1
+-1
+71
+-1
+-1
+26
+52
+42
+17
+-1
+-1
+41
+93
+-1
+-1
+-1
+34
+18
+93
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+53
+-1
+-1
+29
+82
+15
+50
+39
+-1
+72
+36
+83
+98
+-1
+-1
+-1
+-1
+20
+31
+-1
+-1
+-1
+-1
+-1
+32
+62
+-1
+81
+-1
+-1
+28
+-1
+47
+-1
+-1
+-1
+-1
+-1
+-1
+14
+100
+68
+-1
+61
+-1
+-1
+-1
+37
+26
+-1
+96
+-1
+-1
+24
+-1
+-1
+-1
+-1
+-1
+75
+-1
+-1
+47
+90
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_16.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_16.txt
new file mode 100644
index 0000000..edb79c4
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_16.txt
@@ -0,0 +1,100 @@
+14
+45
+32
+81
+-1
+95
+-1
+-1
+-1
+-1
+86
+-1
+-1
+-1
+29
+-1
+93
+-1
+-1
+66
+-1
+44
+-1
+66
+-1
+44
+49
+-1
+-1
+14
+18
+43
+-1
+98
+-1
+-1
+-1
+20
+-1
+67
+-1
+53
+-1
+-1
+-1
+-1
+-1
+-1
+14
+28
+-1
+39
+58
+-1
+26
+-1
+-1
+63
+64
+68
+34
+-1
+99
+63
+-1
+-1
+32
+91
+-1
+32
+63
+-1
+38
+-1
+-1
+38
+-1
+41
+39
+-1
+-1
+-1
+65
+33
+-1
+60
+-1
+-1
+67
+43
+-1
+-1
+74
+94
+-1
+-1
+67
+-1
+-1
+87
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_2.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_2.txt
new file mode 100644
index 0000000..2f13c2a
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_2.txt
@@ -0,0 +1,100 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+38
+-1
+43
+-1
+-1
+-1
+-1
+-1
+-1
+33
+-1
+70
+67
+33
+-1
+-1
+-1
+-1
+17
+-1
+-1
+-1
+-1
+-1
+26
+55
+-1
+-1
+-1
+100
+-1
+69
+-1
+-1
+-1
+-1
+15
+-1
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+68
+-1
+-1
+-1
+82
+56
+-1
+17
+56
+-1
+-1
+-1
+92
+-1
+22
+-1
+-1
+-1
+51
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_3.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_3.txt
new file mode 100644
index 0000000..5a1d718
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_3.txt
@@ -0,0 +1,100 @@
+71
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+33
+62
+-1
+-1
+-1
+-1
+-1
+-1
+74
+-1
+-1
+-1
+-1
+-1
+86
+-1
+-1
+22
+-1
+38
+-1
+40
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+23
+-1
+-1
+-1
+-1
+73
+17
+-1
+-1
+-1
+65
+92
+-1
+85
+34
+-1
+98
+-1
+-1
+-1
+-1
+58
+-1
+59
+-1
+66
+-1
+-1
+-1
+-1
+30
+-1
+-1
+24
+-1
+-1
+-1
+41
+-1
+76
+86
+-1
+-1
+54
+-1
+53
+56
+59
+-1
+14
+43
+22
+-1
+-1
+-1
+55
+94
+-1
+-1
+-1
+-1
+96
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_4.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_4.txt
new file mode 100644
index 0000000..34118de
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_4.txt
@@ -0,0 +1,100 @@
+47
+58
+87
+-1
+-1
+-1
+-1
+-1
+17
+37
+88
+45
+78
+-1
+75
+-1
+32
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+98
+55
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+84
+43
+-1
+-1
+-1
+50
+76
+-1
+-1
+-1
+-1
+81
+69
+76
+-1
+-1
+43
+77
+-1
+-1
+-1
+-1
+-1
+92
+-1
+-1
+60
+-1
+-1
+46
+45
+-1
+-1
+-1
+90
+53
+24
+33
+37
+-1
+80
+-1
+-1
+49
+-1
+-1
+53
+-1
+-1
+63
+-1
+83
+-1
+-1
+-1
+57
+-1
+-1
+-1
+-1
+47
+-1
+64
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5.txt
new file mode 100644
index 0000000..8127599
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5.txt
@@ -0,0 +1,100 @@
+37
+54
+73
+17
+-1
+-1
+-1
+-1
+-1
+82
+76
+15
+-1
+81
+-1
+73
+-1
+39
+57
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+60
+-1
+-1
+-1
+-1
+93
+-1
+36
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+72
+-1
+-1
+-1
+48
+16
+-1
+-1
+-1
+-1
+62
+-1
+-1
+-1
+-1
+88
+87
+63
+80
+-1
+-1
+-1
+37
+27
+-1
+-1
+-1
+25
+-1
+95
+29
+72
+46
+-1
+42
+74
+-1
+14
+-1
+-1
+40
+-1
+57
+-1
+-1
+95
+-1
+-1
+52
+-1
+37
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5_old.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5_old.txt
new file mode 100644
index 0000000..1796809
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_5_old.txt
@@ -0,0 +1,100 @@
+37
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+48
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+27
+-1
+64
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+44
+-1
+-1
+50
+16
+-1
+-1
+98
+-1
+-1
+-1
+-1
+-1
+-1
+99
+-1
+-1
+-1
+-1
+53
+-1
+88
+-1
+-1
+39
+-1
+-1
+78
+-1
+-1
+37
+69
+14
+-1
+72
+-1
+-1
+-1
+48
+-1
+30
+48
+32
+-1
+-1
+98
+-1
+27
+57
+-1
+97
+-1
+-1
+35
+-1
+-1
+-1
+81
+-1
+-1
+-1
+67
+-1
+-1
+-1
+67
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_6.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_6.txt
new file mode 100644
index 0000000..785e04a
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_6.txt
@@ -0,0 +1,100 @@
+16
+37
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+25
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+71
+-1
+-1
+-1
+-1
+79
+-1
+92
+-1
+42
+-1
+-1
+-1
+-1
+54
+-1
+-1
+-1
+21
+-1
+16
+23
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+49
+-1
+43
+28
+-1
+43
+-1
+99
+-1
+38
+-1
+-1
+-1
+50
+40
+-1
+68
+-1
+-1
+15
+-1
+-1
+-1
+-1
+-1
+39
+-1
+-1
+40
+78
+86
+100
+-1
+-1
+-1
+99
+-1
+33
+-1
+-1
+46
+-1
+-1
+-1
+49
+-1
+80
+-1
+73
+77
+88
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_7.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_7.txt
new file mode 100644
index 0000000..1b0e0df
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_7.txt
@@ -0,0 +1,100 @@
+18
+50
+81
+-1
+-1
+-1
+-1
+-1
+-1
+40
+-1
+74
+77
+-1
+-1
+-1
+44
+-1
+-1
+-1
+98
+41
+-1
+59
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+18
+100
+-1
+-1
+-1
+-1
+57
+31
+-1
+-1
+-1
+38
+-1
+-1
+-1
+29
+-1
+32
+-1
+63
+-1
+-1
+-1
+58
+-1
+-1
+48
+-1
+-1
+65
+49
+39
+-1
+-1
+-1
+-1
+35
+-1
+-1
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+65
+74
+-1
+-1
+-1
+34
+32
+-1
+-1
+39
+-1
+41
+-1
+-1
+-1
+-1
+33
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_8.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_8.txt
new file mode 100644
index 0000000..0c57aa4
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_8.txt
@@ -0,0 +1,100 @@
+50
+81
+96
+-1
+-1
+-1
+-1
+14
+75
+-1
+58
+51
+-1
+-1
+68
+-1
+-1
+-1
+42
+-1
+46
+52
+63
+-1
+-1
+88
+-1
+-1
+-1
+20
+-1
+59
+-1
+-1
+-1
+-1
+15
+-1
+-1
+-1
+61
+-1
+-1
+-1
+-1
+73
+91
+-1
+67
+-1
+-1
+47
+-1
+40
+-1
+51
+81
+61
+15
+-1
+-1
+-1
+-1
+-1
+89
+74
+-1
+-1
+18
+53
+41
+-1
+51
+36
+34
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+89
+28
+46
+-1
+54
+22
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_9.txt b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_9.txt
new file mode 100644
index 0000000..143612e
--- /dev/null
+++ b/python/plots/how_many_generations/data/population_size_100_runs/how_many_generations_5x5_k8_population_size_9.txt
@@ -0,0 +1,100 @@
+38
+47
+62
+29
+32
+19
+-1
+-1
+-1
+-1
+-1
+-1
+58
+-1
+-1
+-1
+80
+-1
+-1
+49
+-1
+-1
+-1
+-1
+-1
+15
+81
+16
+-1
+44
+95
+66
+64
+-1
+-1
+72
+-1
+-1
+-1
+35
+-1
+85
+42
+-1
+-1
+-1
+-1
+-1
+78
+-1
+63
+-1
+-1
+57
+23
+-1
+-1
+-1
+-1
+-1
+-1
+98
+51
+-1
+32
+61
+-1
+62
+-1
+53
+-1
+25
+-1
+54
+44
+-1
+73
+49
+-1
+-1
+-1
+-1
+-1
+61
+48
+-1
+-1
+-1
+-1
+-1
+51
+71
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data/times.txt b/python/plots/how_many_generations/data/times.txt
new file mode 100644
index 0000000..26e7d70
--- /dev/null
+++ b/python/plots/how_many_generations/data/times.txt
@@ -0,0 +1,173 @@
+Execution times on i7-6700 CPU @3.40GHz, 4 cores @ 100% workload using
+Python's multiprocessing module
+
+
+####################### 2x2 Chimera grid different K graphs ####################
+
+◾ Params
+population_size = 12
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 1000
+max_generations = 100
+remove_redundancy_probability = 0.01
+m = 2 # grid size
+n = 2 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_2x2 (1000 a time)
+- K2: 2.96s
+- K3: 10.90s
+- K4: 25.61s
+- K5: 52.77s
+- K6: 131.34s
+- K7: 276.01s
+- K8: 632.42s
+- K9: 839.06s
+- K10: ? (around the same time as K9)
+
+
+######################## K8 different Chimera grid sizes #######################
+
+◾ Params
+population_size = 12
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 100
+max_generations = 100
+remove_redundancy_probability = 0.01
+t = 4 # shore size
+
+⏱ how_many_generations_mxm (100 a time)
+- 2x2: 61.78s
+- 3x3: 119.37s
+- 4x4: 201.84s
+- 5x5: 299.73s
+- 6x6: 430.39s
+- 7x7: 502.94s
+- 8x8: 638.90s
+- 9x9: 803.30s
+
+
+####################### K8 different population sizes (100) ####################
+
+◾ Params
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 100
+max_generations = 100
+remove_redundancy_probability = 0.01
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_population_size (100 a time)
+- 1: 38.82s
+- 2: 61.40s
+- 3: 90.75s
+- 4: 109.35s
+- 5: 140.66s
+- 6: 168.38s
+- 7: 192.45s
+- 8: 205.01s
+- 9: 233.09s
+- 10: 236.01s
+- 11: 251.86s
+- 12: 288.17s
+- 13: 339.22s
+- 14: 378.01s
+- 15: 343.30s
+- 16: 371.73s
+
+
+###################### K8 different population sizes (100) #####################
+
+◾ Params
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 100
+max_generations = 600
+remove_redundancy_probability = 0.01
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_population_size (100 a time)
+- 1: 128.87s
+- 2: 224.79s
+- 3: 281.21s
+- 4: 259.75s
+- 5: 385.54s
+- 6: 408.23s
+- 7: 505.68s
+- 8: 648.50s
+- 9: 652.14s
+- 10: 718.90s
+- 11: 618.84s
+- 12: 862.02s
+- 13: 843.26s
+- 14: 914.88s
+- 15: 435.01s
+- 16: 382.50s
+- 17: 607.80s (started to run another task with 100%)
+- 18: 735.05s
+- 19:
+- 20:
+
+
+####################### K8 different population sizes (1000) ###################
+
+Marc💥
+◾ Params
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 1000
+max_generations = 100
+remove_redundancy_probability = 0.01
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_population_size (1000 a time)
+
+
+###################### K8 different population sizes (1000) ####################
+
+Marc💥
+◾ Params
+max_mutation_trials = 30
+mutation_extend_to_free_neighbors_probability = 0.3
+max_total = 1000
+max_generations = 600
+remove_redundancy_probability = 0.01
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_population_size (1000 a time)
+
+
+######################## K8 different probabilities (50) #######################
+
+◾ Params
+population_size=4,
+max_mutation_trials=30
+max_total = 50
+max_generations = 600
+remove_redundancy_probability = 0.01
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+⏱ how_many_generations_extend_to_free_probability (50 a time)
+- 0.00: 132.61s
+- 0.11: 276.20s
+- 0.22: 359.29s
+- 0.33: 272.75s
+- 0.44: 269.85s
+- 0.55: 301.38s
+- 0.66: 326.49s
+- 0.77: 332.97s
+- 0.88: 357.85s
+- 1.00: 226.74s
+
\ No newline at end of file
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/docker-compose.yml b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/docker-compose.yml
new file mode 100644
index 0000000..517b2af
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/docker-compose.yml
@@ -0,0 +1,21 @@
+services:
+ major-miner:
+ build: .
+ container_name: major-miner
+ environment:
+ CORE_PERCENTAGE: 90
+ MAX_MUTATION_TRIALS: 30
+ PROB_EXTEND_TO_FREE_NEIGHBOR: 0.3
+ MAX_TOTAL: 1000
+ MAX_GENERATIONS: 600
+ PROB_REMOVE_REDUNDANCY: 0.01
+ GRID_M: 5
+ GRID_N: 5
+ K_GRAPH: 8
+ POPSIZE_MIN: 1
+ POPSIZE_MAX: 20
+
+ volumes:
+ - type: bind
+ source: ./out
+ target: /app/out
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution.py b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution.py
new file mode 100644
index 0000000..7452778
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution.py
@@ -0,0 +1,143 @@
+# Move this file to src/solver to start
+# Disable logger!
+
+import logging
+import multiprocessing
+import os
+import shutil
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.drawing.draw import DrawEmbedding
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+################################# Params #######################################
+
+max_total = 10
+max_generations = 600
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+d = DrawEmbedding(m, n, t)
+
+
+def different_params():
+ # --- Clear
+ try:
+ shutil.rmtree('./out/')
+ except FileNotFoundError:
+ pass
+ os.mkdir('./out')
+
+ for population_size in range(1, 21):
+ print(f'Started population size {population_size}')
+ graph_number = 8
+ graph = TestGraph.k(graph_number)
+ start_time = time.time()
+ start_multiprocessing((graph, population_size), f'k{graph_number}popsize{population_size}')
+ duration = time.time() - start_time
+ print(f'Duration for population size {population_size}: {duration} s')
+
+
+def start_multiprocessing(plot_params, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 90)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, plot_params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/howManyGenerations_{m}x{n}_{max_total}_{max_generations}gen_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(plot_params, j) -> int:
+ solver = EmbeddingSolver(plot_params[0], m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver, plot_params)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ save_embedding(*solver.get_embedding(), d, f'{j}-{i}final', plot_params,
+ title=f'Generation {i} (final with redundancy removed)')
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver, plot_params) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ evo_params = EvolutionParams(
+ population_size=plot_params[1],
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3
+ )
+
+ child = solver.generate_population_and_select(evo_params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+def save_embedding(nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H, d: DrawEmbedding, name: str, plot_params, title=''):
+ logger.info('')
+ logger.info('🎈 Current embedding')
+ logger.info(f'edges: {edges}')
+ logger.info(f'mapping_G_to_H: {mapping_G_to_H}')
+
+ d.draw_whole_embedding_step(nodes, edges, mapping_G_to_H, title=title)
+
+ folder_path = f'./out/popsize{plot_params[1]}'
+ if not os.path.exists(folder_path):
+ os.mkdir(folder_path)
+ d.save_and_clear(os.path.join(folder_path, f'{name}.svg'))
+
+
+if __name__ == "__main__":
+ different_params()
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution_dockerized.py b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution_dockerized.py
new file mode 100644
index 0000000..a817c51
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/evolution_dockerized.py
@@ -0,0 +1,144 @@
+# Move this file to src/solver to start
+# Disable logger!
+
+import logging
+import multiprocessing
+import os
+import shutil
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.drawing.draw import DrawEmbedding
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+################################# Params #######################################
+
+max_total = int(os.getenv('MAX_TOTAL', 300))
+max_generations = int(os.getenv('MAX_GENERATIONS', 600))
+remove_redundancy_probability = float(os.getenv('PROB_REMOVE_REDUNDANCY', 0.01))
+
+# Chimera graph
+m = int(os.getenv('GRID_M', 5)) # grid size
+n = int(os.getenv('GRID_N', 5)) # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+d = DrawEmbedding(m, n, t)
+
+
+def different_params():
+ # --- Clear
+ try:
+ shutil.rmtree('./out/')
+ except FileNotFoundError:
+ pass
+ os.mkdir('./out')
+
+ for population_size in range(int(os.getenv('POPSIZE_MIN', 1)), int(os.getenv('POPSIZE_MAX', 20)) + 1):
+ print(f'Started population size {population_size}')
+ graph_number = int(os.getenv('K_GRAPH', 8))
+ graph = TestGraph.k(graph_number)
+ start_time = time.time()
+ start_multiprocessing((graph, population_size), f'k{graph_number}popsize{population_size}')
+ duration = time.time() - start_time
+ print(f'Duration for population size {population_size}: {duration} s')
+
+
+def start_multiprocessing(plot_params, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 75)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, plot_params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/howManyGenerations_{m}x{n}_{max_total}_{max_generations}gen_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(plot_params, j) -> int:
+ solver = EmbeddingSolver(plot_params[0], m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver, plot_params)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ save_embedding(*solver.get_embedding(), d, f'{j}-{i}final', plot_params,
+ title=f'Generation {i} (final with redundancy removed)')
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver, plot_params) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ evo_params = EvolutionParams(
+ population_size=plot_params[1],
+ max_mutation_trials=int(os.getenv('MAX_MUTATION_TRIALS', 30)),
+ mutation_extend_to_free_neighbors_probability=float(
+ os.getenv('PROB_EXTEND_TO_FREE_NEIGHBOR', 0.3))
+ )
+
+ child = solver.generate_population_and_select(evo_params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+def save_embedding(nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H, d: DrawEmbedding, name: str, plot_params, title=''):
+ logger.info('')
+ logger.info('🎈 Current embedding')
+ logger.info(f'edges: {edges}')
+ logger.info(f'mapping_G_to_H: {mapping_G_to_H}')
+
+ d.draw_whole_embedding_step(nodes, edges, mapping_G_to_H, title=title)
+
+ folder_path = f'./out/popsize{plot_params[1]}'
+ if not os.path.exists(folder_path):
+ os.mkdir(folder_path)
+ d.save_and_clear(os.path.join(folder_path, f'{name}.svg'))
+
+
+if __name__ == "__main__":
+ different_params()
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize1.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize1.txt
new file mode 100644
index 0000000..1c5fe31
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize1.txt
@@ -0,0 +1,10 @@
+241
+-1
+346
+-1
+477
+-1
+88
+242
+310
+450
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize10.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize10.txt
new file mode 100644
index 0000000..a44056c
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize10.txt
@@ -0,0 +1,10 @@
+43
+59
+41
+20
+116
+24
+185
+346
+475
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize11.txt
new file mode 100644
index 0000000..942cd39
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize11.txt
@@ -0,0 +1,10 @@
+32
+33
+30
+60
+58
+84
+96
+222
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize12.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize12.txt
new file mode 100644
index 0000000..684c8ce
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize12.txt
@@ -0,0 +1,10 @@
+17
+41
+50
+27
+200
+163
+191
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize13.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize13.txt
new file mode 100644
index 0000000..8bd8391
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize13.txt
@@ -0,0 +1,10 @@
+49
+80
+14
+111
+124
+144
+58
+76
+85
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize14.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize14.txt
new file mode 100644
index 0000000..7b92053
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize14.txt
@@ -0,0 +1,10 @@
+40
+15
+52
+168
+280
+228
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize15.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize15.txt
new file mode 100644
index 0000000..1ab07b7
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize15.txt
@@ -0,0 +1,10 @@
+23
+62
+70
+85
+30
+43
+191
+175
+106
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize16.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize16.txt
new file mode 100644
index 0000000..1c250d4
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize16.txt
@@ -0,0 +1,10 @@
+22
+50
+97
+99
+128
+120
+115
+105
+203
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize17.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize17.txt
new file mode 100644
index 0000000..b1c0096
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize17.txt
@@ -0,0 +1,10 @@
+85
+18
+131
+172
+22
+58
+321
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize18.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize18.txt
new file mode 100644
index 0000000..b7205cb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize18.txt
@@ -0,0 +1,10 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize19.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize19.txt
new file mode 100644
index 0000000..b7205cb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize19.txt
@@ -0,0 +1,10 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize2.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize2.txt
new file mode 100644
index 0000000..7f24cb8
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize2.txt
@@ -0,0 +1,10 @@
+28
+79
+164
+-1
+561
+-1
+51
+-1
+99
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize20.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize20.txt
new file mode 100644
index 0000000..b7205cb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize20.txt
@@ -0,0 +1,10 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize3.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize3.txt
new file mode 100644
index 0000000..9783af3
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize3.txt
@@ -0,0 +1,10 @@
+78
+74
+161
+123
+215
+242
+159
+145
+312
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize4.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize4.txt
new file mode 100644
index 0000000..8d92ce0
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize4.txt
@@ -0,0 +1,10 @@
+14
+73
+100
+173
+88
+35
+220
+187
+182
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize5.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize5.txt
new file mode 100644
index 0000000..1640eec
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize5.txt
@@ -0,0 +1,10 @@
+16
+25
+115
+126
+215
+26
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize6.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize6.txt
new file mode 100644
index 0000000..21e06e5
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize6.txt
@@ -0,0 +1,10 @@
+64
+75
+62
+78
+16
+48
+247
+140
+238
+442
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize7.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize7.txt
new file mode 100644
index 0000000..46f53ab
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize7.txt
@@ -0,0 +1,10 @@
+26
+29
+71
+57
+14
+75
+50
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize8.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize8.txt
new file mode 100644
index 0000000..cd62020
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize8.txt
@@ -0,0 +1,10 @@
+14
+43
+69
+112
+185
+19
+33
+218
+282
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize9.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize9.txt
new file mode 100644
index 0000000..1661b32
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize9.txt
@@ -0,0 +1,10 @@
+104
+158
+178
+80
+277
+25
+289
+108
+498
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize1.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize1.txt
new file mode 100644
index 0000000..c0e44ea
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize1.txt
@@ -0,0 +1,300 @@
+316
+136
+21
+-1
+123
+-1
+123
+286
+516
+-1
+-1
+241
+110
+133
+242
+189
+495
+-1
+76
+80
+-1
+149
+44
+-1
+-1
+140
+-1
+126
+-1
+302
+271
+171
+-1
+-1
+39
+-1
+36
+138
+357
+142
+-1
+149
+350
+260
+322
+125
+66
+60
+-1
+29
+192
+-1
+140
+105
+134
+40
+57
+121
+233
+-1
+-1
+204
+-1
+-1
+222
+62
+108
+24
+42
+-1
+123
+143
+388
+354
+257
+192
+95
+-1
+241
+186
+482
+59
+62
+56
+52
+249
+-1
+123
+-1
+-1
+-1
+94
+102
+310
+94
+187
+174
+169
+230
+174
+530
+-1
+409
+242
+-1
+175
+-1
+283
+-1
+61
+-1
+177
+374
+437
+91
+207
+20
+219
+139
+53
+55
+148
+-1
+35
+199
+-1
+345
+-1
+128
+212
+384
+-1
+154
+20
+50
+155
+-1
+548
+197
+-1
+-1
+134
+25
+513
+105
+143
+237
+231
+-1
+234
+264
+113
+-1
+271
+-1
+320
+-1
+-1
+352
+319
+174
+-1
+-1
+142
+398
+-1
+332
+57
+425
+-1
+-1
+403
+406
+85
+145
+-1
+-1
+464
+129
+-1
+154
+197
+-1
+197
+295
+232
+-1
+-1
+141
+-1
+178
+380
+102
+38
+315
+161
+-1
+218
+127
+376
+211
+252
+140
+298
+-1
+146
+52
+100
+112
+333
+-1
+321
+402
+-1
+61
+22
+58
+193
+191
+-1
+18
+283
+-1
+169
+252
+230
+-1
+234
+31
+182
+88
+257
+166
+116
+367
+134
+104
+103
+-1
+-1
+363
+-1
+179
+33
+111
+-1
+199
+444
+186
+-1
+537
+427
+593
+218
+102
+197
+-1
+360
+83
+28
+39
+366
+21
+190
+402
+134
+56
+166
+-1
+317
+235
+175
+54
+273
+60
+186
+313
+175
+201
+234
+89
+199
+140
+457
+-1
+170
+178
+229
+351
+26
+169
+103
+-1
+263
+169
+119
+564
+461
+262
+156
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize10.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize10.txt
new file mode 100644
index 0000000..1b15f4e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize10.txt
@@ -0,0 +1,300 @@
+29
+134
+63
+138
+26
+-1
+44
+-1
+214
+-1
+206
+83
+-1
+81
+33
+113
+42
+53
+17
+534
+72
+66
+113
+295
+209
+51
+21
+-1
+365
+59
+526
+222
+428
+223
+31
+260
+-1
+-1
+64
+324
+33
+182
+75
+46
+201
+31
+175
+74
+56
+18
+174
+66
+-1
+214
+25
+-1
+18
+113
+-1
+26
+38
+30
+58
+294
+-1
+48
+105
+137
+96
+34
+14
+90
+131
+364
+121
+-1
+198
+337
+37
+23
+16
+82
+113
+35
+-1
+128
+236
+235
+101
+276
+128
+47
+246
+63
+59
+82
+-1
+70
+147
+70
+32
+-1
+-1
+18
+61
+35
+57
+78
+33
+467
+125
+59
+-1
+119
+64
+185
+-1
+60
+35
+54
+147
+-1
+188
+349
+158
+146
+171
+28
+237
+27
+-1
+250
+529
+180
+47
+99
+387
+53
+19
+-1
+28
+298
+206
+41
+63
+19
+82
+202
+571
+60
+28
+47
+143
+230
+40
+-1
+149
+188
+179
+-1
+148
+70
+46
+179
+33
+30
+182
+17
+66
+29
+39
+193
+15
+73
+33
+96
+58
+148
+56
+105
+67
+61
+101
+-1
+49
+24
+152
+36
+21
+-1
+17
+14
+-1
+20
+27
+43
+119
+332
+73
+106
+27
+252
+143
+415
+28
+44
+147
+469
+303
+166
+189
+71
+-1
+105
+-1
+190
+88
+41
+-1
+27
+185
+116
+16
+103
+190
+26
+223
+412
+373
+26
+-1
+365
+139
+80
+300
+256
+-1
+45
+280
+51
+91
+15
+46
+91
+256
+-1
+53
+168
+188
+209
+-1
+38
+-1
+188
+237
+66
+-1
+46
+30
+-1
+184
+23
+82
+37
+25
+123
+84
+257
+195
+93
+-1
+14
+75
+522
+15
+-1
+83
+254
+213
+98
+115
+262
+200
+118
+100
+473
+60
+-1
+206
+15
+137
+-1
+268
+36
+68
+130
+-1
+-1
+75
+337
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize11.txt
new file mode 100644
index 0000000..aa9075d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize11.txt
@@ -0,0 +1,300 @@
+51
+155
+52
+102
+34
+74
+-1
+177
+52
+112
+-1
+119
+50
+115
+220
+136
+-1
+-1
+58
+18
+-1
+22
+96
+42
+22
+45
+144
+241
+75
+-1
+149
+14
+-1
+15
+452
+-1
+213
+93
+51
+-1
+-1
+41
+-1
+57
+-1
+-1
+85
+23
+439
+106
+45
+-1
+19
+33
+21
+29
+53
+15
+18
+36
+135
+-1
+43
+77
+16
+-1
+498
+20
+-1
+66
+105
+36
+109
+17
+190
+102
+231
+16
+132
+-1
+101
+515
+-1
+168
+230
+53
+128
+36
+95
+102
+61
+69
+42
+65
+72
+382
+42
+99
+34
+24
+80
+43
+-1
+419
+105
+219
+125
+-1
+108
+31
+37
+-1
+240
+77
+315
+23
+74
+-1
+58
+-1
+47
+204
+34
+63
+83
+249
+17
+67
+163
+22
+42
+47
+-1
+28
+142
+-1
+64
+207
+-1
+75
+81
+48
+148
+30
+44
+-1
+99
+19
+-1
+140
+50
+76
+185
+30
+-1
+99
+23
+67
+188
+96
+431
+116
+50
+48
+183
+-1
+303
+565
+60
+76
+27
+-1
+-1
+16
+36
+224
+78
+44
+50
+-1
+-1
+21
+144
+198
+189
+31
+281
+-1
+28
+-1
+172
+38
+40
+-1
+103
+49
+290
+242
+130
+-1
+-1
+72
+-1
+61
+36
+38
+250
+75
+-1
+-1
+-1
+33
+32
+46
+-1
+47
+26
+250
+82
+66
+74
+14
+47
+60
+133
+17
+98
+52
+-1
+-1
+135
+16
+25
+18
+-1
+14
+66
+-1
+20
+15
+159
+363
+246
+334
+190
+39
+31
+73
+-1
+33
+50
+330
+229
+-1
+15
+52
+-1
+91
+62
+547
+54
+102
+33
+58
+78
+23
+238
+183
+104
+-1
+-1
+24
+-1
+33
+116
+392
+-1
+156
+14
+178
+160
+-1
+161
+106
+326
+17
+65
+34
+254
+38
+-1
+54
+22
+216
+37
+168
+99
+47
+229
+342
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize12.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize12.txt
new file mode 100644
index 0000000..6ef0fef
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize12.txt
@@ -0,0 +1,300 @@
+377
+247
+-1
+-1
+45
+324
+348
+416
+51
+29
+63
+34
+147
+154
+30
+261
+-1
+51
+56
+198
+101
+35
+266
+107
+218
+-1
+85
+-1
+82
+231
+23
+245
+73
+65
+65
+455
+74
+14
+-1
+25
+124
+24
+-1
+200
+-1
+-1
+111
+186
+42
+180
+65
+-1
+73
+269
+62
+292
+114
+49
+88
+232
+27
+114
+-1
+125
+-1
+357
+60
+65
+164
+76
+-1
+21
+16
+367
+105
+20
+254
+70
+-1
+118
+-1
+43
+35
+-1
+14
+17
+116
+80
+40
+17
+28
+119
+23
+76
+-1
+102
+401
+89
+186
+30
+147
+52
+26
+81
+17
+16
+61
+120
+157
+358
+152
+311
+245
+-1
+87
+24
+-1
+43
+60
+67
+122
+88
+169
+35
+-1
+67
+16
+140
+75
+31
+-1
+186
+-1
+133
+59
+28
+36
+38
+88
+63
+28
+-1
+-1
+-1
+169
+23
+68
+56
+104
+-1
+18
+46
+48
+-1
+125
+24
+124
+182
+52
+276
+-1
+-1
+-1
+-1
+392
+93
+18
+88
+15
+51
+410
+210
+43
+102
+116
+54
+413
+50
+86
+-1
+56
+213
+59
+199
+42
+129
+-1
+-1
+67
+67
+35
+14
+31
+95
+45
+108
+79
+41
+93
+61
+44
+35
+-1
+75
+-1
+18
+81
+97
+22
+-1
+73
+147
+167
+69
+486
+-1
+175
+557
+32
+16
+26
+206
+66
+14
+73
+156
+-1
+26
+146
+21
+19
+74
+-1
+64
+273
+144
+-1
+49
+298
+46
+258
+37
+496
+75
+139
+519
+150
+82
+70
+87
+131
+241
+93
+-1
+182
+308
+52
+19
+59
+16
+76
+97
+116
+-1
+36
+-1
+111
+162
+-1
+140
+413
+370
+322
+64
+-1
+25
+47
+-1
+133
+-1
+205
+95
+94
+102
+14
+74
+47
+33
+-1
+26
+39
+48
+61
+134
+25
+-1
+232
+-1
+377
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize2.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize2.txt
new file mode 100644
index 0000000..5aaceec
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize2.txt
@@ -0,0 +1,300 @@
+88
+74
+-1
+-1
+173
+-1
+204
+100
+28
+-1
+236
+69
+-1
+199
+70
+142
+197
+28
+268
+170
+-1
+197
+50
+96
+169
+-1
+-1
+121
+58
+216
+92
+258
+-1
+93
+-1
+101
+49
+164
+243
+231
+56
+289
+54
+-1
+17
+129
+150
+140
+28
+59
+250
+73
+348
+258
+140
+129
+-1
+96
+29
+-1
+19
+75
+-1
+75
+-1
+171
+234
+83
+237
+85
+81
+-1
+-1
+64
+18
+229
+-1
+356
+344
+83
+142
+141
+58
+111
+64
+277
+190
+45
+54
+42
+110
+131
+310
+220
+217
+176
+37
+245
+44
+48
+-1
+86
+159
+233
+471
+25
+-1
+232
+242
+-1
+144
+49
+230
+-1
+57
+-1
+24
+105
+345
+312
+73
+557
+38
+-1
+131
+324
+44
+-1
+392
+72
+47
+-1
+28
+126
+-1
+122
+239
+-1
+-1
+46
+35
+148
+74
+103
+85
+239
+71
+256
+-1
+-1
+249
+72
+39
+211
+191
+113
+75
+105
+-1
+-1
+131
+410
+-1
+48
+158
+39
+90
+109
+-1
+82
+-1
+93
+236
+115
+249
+188
+211
+68
+-1
+-1
+102
+131
+75
+143
+77
+-1
+-1
+63
+315
+-1
+206
+216
+35
+-1
+49
+33
+257
+312
+69
+342
+265
+153
+244
+-1
+114
+444
+591
+107
+169
+97
+429
+475
+47
+-1
+52
+297
+128
+127
+98
+-1
+145
+178
+15
+284
+167
+-1
+242
+82
+53
+172
+-1
+106
+132
+127
+70
+184
+-1
+241
+27
+83
+-1
+206
+68
+201
+211
+23
+63
+64
+-1
+127
+146
+355
+61
+243
+-1
+198
+74
+24
+-1
+30
+148
+111
+310
+52
+-1
+242
+-1
+39
+341
+-1
+73
+341
+-1
+53
+152
+-1
+-1
+72
+478
+-1
+-1
+282
+201
+270
+63
+144
+-1
+418
+48
+350
+269
+-1
+54
+119
+547
+38
+143
+264
+-1
+499
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize3.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize3.txt
new file mode 100644
index 0000000..77c483b
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize3.txt
@@ -0,0 +1,300 @@
+209
+238
+240
+158
+76
+122
+-1
+-1
+86
+237
+105
+173
+104
+43
+38
+32
+97
+91
+25
+-1
+437
+-1
+47
+-1
+41
+-1
+63
+84
+30
+173
+237
+340
+17
+31
+128
+353
+298
+-1
+-1
+-1
+73
+111
+351
+-1
+282
+30
+167
+315
+133
+-1
+149
+119
+210
+50
+225
+304
+19
+-1
+149
+411
+69
+32
+223
+84
+134
+64
+-1
+75
+187
+276
+105
+118
+173
+-1
+146
+41
+41
+-1
+60
+-1
+206
+67
+-1
+73
+192
+244
+-1
+84
+42
+97
+95
+14
+-1
+104
+245
+149
+232
+213
+157
+-1
+48
+106
+90
+94
+91
+16
+102
+42
+83
+111
+250
+82
+469
+105
+133
+134
+57
+-1
+-1
+-1
+261
+53
+87
+101
+242
+74
+278
+145
+146
+84
+55
+98
+73
+-1
+125
+215
+219
+270
+231
+89
+459
+397
+153
+187
+14
+43
+25
+155
+54
+-1
+53
+84
+16
+229
+68
+-1
+151
+329
+-1
+126
+54
+48
+14
+372
+56
+-1
+33
+32
+135
+249
+285
+129
+81
+-1
+154
+32
+104
+-1
+522
+444
+46
+21
+-1
+86
+-1
+47
+227
+101
+-1
+158
+18
+-1
+86
+133
+-1
+295
+34
+75
+106
+18
+23
+-1
+190
+-1
+161
+147
+57
+109
+76
+109
+242
+90
+53
+-1
+152
+237
+41
+285
+242
+320
+115
+100
+148
+-1
+59
+-1
+176
+127
+75
+-1
+127
+197
+47
+127
+62
+221
+-1
+308
+255
+103
+248
+-1
+-1
+76
+-1
+204
+209
+179
+62
+141
+74
+52
+215
+321
+82
+27
+425
+433
+88
+389
+224
+-1
+247
+14
+27
+145
+287
+52
+67
+50
+251
+43
+164
+-1
+-1
+354
+-1
+47
+61
+74
+173
+197
+161
+78
+509
+222
+-1
+115
+313
+481
+38
+105
+-1
+-1
+243
+-1
+-1
+16
+192
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize4.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize4.txt
new file mode 100644
index 0000000..0857f29
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize4.txt
@@ -0,0 +1,300 @@
+45
+167
+182
+73
+-1
+-1
+18
+38
+70
+145
+50
+-1
+17
+15
+37
+388
+289
+176
+-1
+197
+55
+80
+132
+-1
+30
+-1
+82
+317
+62
+165
+165
+-1
+191
+-1
+156
+275
+34
+192
+81
+82
+93
+59
+153
+-1
+41
+88
+82
+160
+55
+182
+-1
+55
+417
+-1
+-1
+143
+52
+23
+17
+86
+-1
+20
+-1
+-1
+542
+158
+44
+14
+124
+69
+84
+41
+-1
+116
+139
+90
+69
+161
+52
+121
+133
+220
+347
+-1
+67
+390
+318
+40
+54
+40
+-1
+172
+175
+207
+136
+17
+28
+-1
+28
+68
+82
+15
+237
+25
+-1
+115
+86
+49
+402
+163
+80
+97
+229
+16
+90
+111
+176
+112
+14
+276
+47
+48
+94
+146
+137
+30
+138
+-1
+35
+207
+-1
+20
+23
+112
+316
+133
+52
+43
+44
+70
+16
+147
+37
+106
+127
+568
+190
+205
+47
+-1
+20
+43
+37
+63
+-1
+16
+429
+72
+89
+-1
+202
+169
+275
+107
+118
+119
+221
+48
+87
+30
+-1
+53
+-1
+23
+194
+164
+-1
+15
+94
+90
+213
+142
+308
+251
+23
+198
+78
+254
+382
+-1
+302
+-1
+66
+44
+63
+80
+101
+134
+377
+54
+16
+-1
+119
+55
+191
+-1
+235
+177
+-1
+30
+105
+147
+184
+79
+-1
+45
+82
+181
+359
+55
+40
+44
+47
+60
+45
+72
+248
+-1
+-1
+226
+112
+76
+107
+165
+-1
+113
+-1
+-1
+94
+588
+-1
+526
+153
+160
+160
+147
+139
+-1
+140
+72
+15
+-1
+51
+-1
+40
+54
+28
+200
+76
+-1
+383
+270
+141
+202
+418
+106
+189
+27
+113
+-1
+159
+224
+-1
+-1
+-1
+215
+117
+81
+349
+243
+75
+58
+181
+133
+19
+50
+17
+16
+249
+56
+36
+17
+211
+38
+210
+285
+199
+417
+104
+228
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize5.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize5.txt
new file mode 100644
index 0000000..05f4538
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize5.txt
@@ -0,0 +1,300 @@
+39
+48
+46
+121
+103
+67
+35
+184
+62
+71
+84
+132
+343
+-1
+-1
+40
+95
+216
+97
+355
+261
+45
+39
+16
+-1
+-1
+409
+38
+186
+213
+36
+425
+128
+90
+-1
+-1
+126
+57
+39
+24
+140
+-1
+208
+-1
+-1
+122
+21
+-1
+56
+53
+103
+33
+182
+78
+-1
+84
+229
+110
+32
+319
+288
+307
+535
+51
+98
+151
+43
+188
+212
+138
+-1
+49
+109
+36
+223
+310
+155
+67
+104
+137
+213
+35
+134
+-1
+100
+120
+56
+80
+162
+128
+126
+451
+54
+115
+121
+17
+191
+308
+339
+41
+16
+102
+41
+342
+98
+19
+42
+79
+282
+-1
+50
+140
+119
+85
+14
+26
+81
+500
+34
+136
+247
+-1
+140
+151
+548
+137
+43
+16
+63
+-1
+27
+-1
+86
+31
+118
+334
+215
+154
+105
+48
+247
+243
+45
+40
+136
+-1
+188
+-1
+75
+189
+-1
+19
+26
+28
+23
+47
+57
+187
+32
+44
+38
+280
+69
+407
+48
+198
+97
+192
+15
+34
+-1
+243
+29
+62
+21
+38
+74
+136
+396
+198
+326
+201
+199
+-1
+132
+25
+197
+16
+68
+15
+119
+72
+22
+150
+41
+197
+-1
+54
+62
+-1
+16
+-1
+15
+22
+35
+75
+85
+-1
+133
+141
+-1
+26
+144
+191
+58
+85
+106
+46
+230
+-1
+19
+220
+28
+-1
+108
+346
+-1
+23
+292
+37
+26
+40
+14
+57
+206
+22
+-1
+43
+193
+60
+93
+78
+53
+83
+-1
+43
+-1
+78
+103
+159
+16
+154
+206
+-1
+128
+380
+245
+-1
+15
+-1
+166
+263
+121
+-1
+43
+-1
+14
+167
+-1
+-1
+14
+153
+39
+48
+-1
+200
+37
+38
+302
+76
+448
+35
+55
+114
+-1
+194
+28
+-1
+49
+168
+56
+191
+461
+74
+169
+392
+243
+279
+511
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize6.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize6.txt
new file mode 100644
index 0000000..ed94a53
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize6.txt
@@ -0,0 +1,300 @@
+24
+19
+51
+332
+-1
+218
+25
+-1
+58
+102
+87
+-1
+58
+220
+-1
+333
+41
+45
+61
+179
+410
+58
+102
+-1
+57
+217
+436
+66
+46
+294
+497
+87
+24
+-1
+68
+227
+39
+220
+92
+16
+221
+22
+-1
+218
+31
+38
+345
+-1
+45
+44
+42
+429
+22
+81
+-1
+75
+89
+233
+64
+37
+56
+71
+128
+86
+39
+35
+257
+23
+165
+53
+64
+104
+-1
+110
+21
+87
+-1
+39
+105
+31
+230
+-1
+259
+-1
+-1
+76
+-1
+78
+335
+228
+-1
+29
+-1
+185
+29
+182
+157
+49
+525
+31
+43
+570
+69
+229
+95
+233
+189
+46
+31
+92
+107
+25
+-1
+65
+196
+20
+-1
+78
+116
+162
+186
+48
+28
+44
+202
+272
+-1
+186
+129
+30
+40
+166
+77
+-1
+32
+155
+39
+478
+-1
+34
+188
+102
+-1
+-1
+24
+14
+197
+-1
+80
+40
+-1
+60
+134
+28
+67
+26
+-1
+92
+72
+61
+-1
+94
+141
+154
+-1
+-1
+93
+198
+187
+310
+77
+286
+139
+43
+486
+100
+162
+220
+62
+272
+362
+116
+230
+95
+15
+186
+107
+58
+15
+110
+-1
+14
+22
+-1
+-1
+194
+20
+30
+-1
+74
+182
+186
+-1
+98
+47
+-1
+14
+91
+130
+111
+18
+-1
+169
+44
+18
+95
+-1
+61
+228
+76
+46
+105
+202
+17
+43
+222
+16
+102
+46
+-1
+-1
+112
+155
+184
+214
+43
+207
+245
+116
+144
+94
+135
+28
+-1
+64
+76
+90
+43
+174
+-1
+14
+143
+98
+50
+44
+-1
+28
+37
+-1
+94
+207
+-1
+95
+175
+-1
+-1
+15
+83
+57
+150
+356
+448
+52
+36
+200
+98
+24
+18
+34
+197
+48
+14
+76
+24
+28
+194
+-1
+-1
+78
+293
+141
+261
+243
+74
+130
+118
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize7.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize7.txt
new file mode 100644
index 0000000..396e411
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize7.txt
@@ -0,0 +1,300 @@
+42
+21
+76
+139
+59
+181
+63
+244
+35
+57
+193
+-1
+22
+-1
+-1
+217
+288
+55
+71
+204
+-1
+251
+62
+-1
+82
+-1
+224
+98
+172
+36
+589
+-1
+203
+22
+30
+93
+-1
+79
+233
+121
+55
+44
+54
+174
+538
+-1
+127
+-1
+61
+219
+-1
+193
+82
+-1
+-1
+-1
+244
+141
+139
+37
+23
+-1
+262
+87
+255
+-1
+205
+27
+42
+77
+-1
+156
+15
+28
+-1
+142
+-1
+248
+45
+30
+-1
+355
+34
+-1
+393
+40
+20
+187
+177
+24
+-1
+27
+-1
+347
+14
+-1
+-1
+349
+95
+164
+101
+-1
+-1
+218
+77
+37
+-1
+-1
+475
+103
+186
+475
+110
+-1
+36
+154
+155
+122
+95
+-1
+140
+164
+187
+185
+153
+-1
+85
+255
+137
+249
+134
+152
+498
+18
+24
+172
+34
+171
+-1
+-1
+76
+42
+14
+-1
+-1
+-1
+295
+40
+141
+-1
+178
+177
+35
+167
+-1
+60
+-1
+79
+162
+146
+149
+198
+53
+387
+-1
+65
+-1
+-1
+-1
+122
+65
+100
+38
+49
+388
+179
+266
+-1
+48
+504
+154
+47
+-1
+42
+-1
+-1
+38
+135
+90
+122
+-1
+168
+65
+92
+65
+42
+218
+47
+177
+22
+-1
+124
+-1
+-1
+236
+60
+132
+105
+83
+-1
+119
+-1
+35
+38
+21
+-1
+120
+16
+255
+-1
+-1
+143
+-1
+207
+49
+32
+141
+525
+88
+-1
+67
+309
+-1
+-1
+236
+200
+75
+-1
+191
+64
+-1
+72
+262
+61
+19
+-1
+365
+111
+-1
+229
+173
+100
+112
+91
+-1
+70
+240
+66
+14
+122
+137
+196
+151
+202
+176
+-1
+44
+49
+51
+143
+57
+162
+-1
+241
+21
+169
+106
+20
+-1
+210
+65
+127
+472
+97
+-1
+-1
+-1
+63
+54
+109
+143
+147
+49
+38
+20
+171
+58
+258
+215
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize8.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize8.txt
new file mode 100644
index 0000000..cf940ac
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize8.txt
@@ -0,0 +1,300 @@
+62
+397
+37
+25
+-1
+-1
+40
+170
+169
+20
+76
+74
+61
+187
+174
+-1
+167
+228
+28
+-1
+14
+86
+256
+27
+-1
+540
+77
+14
+-1
+152
+174
+-1
+390
+43
+77
+91
+20
+52
+151
+228
+-1
+25
+-1
+-1
+27
+-1
+56
+336
+76
+63
+118
+64
+508
+118
+140
+-1
+60
+-1
+-1
+95
+84
+67
+90
+59
+243
+191
+16
+34
+242
+41
+91
+112
+109
+47
+15
+132
+251
+35
+69
+55
+95
+47
+97
+164
+15
+394
+219
+432
+374
+328
+15
+-1
+21
+64
+194
+39
+59
+223
+15
+14
+102
+104
+84
+273
+101
+49
+61
+99
+-1
+41
+51
+37
+-1
+115
+44
+329
+425
+51
+165
+41
+132
+88
+15
+-1
+90
+139
+24
+36
+31
+185
+254
+52
+-1
+161
+116
+66
+238
+194
+193
+60
+90
+-1
+25
+64
+135
+465
+96
+-1
+182
+588
+218
+190
+73
+-1
+24
+210
+18
+-1
+53
+335
+63
+-1
+-1
+313
+116
+71
+14
+85
+74
+-1
+31
+-1
+53
+108
+39
+35
+82
+-1
+62
+312
+65
+118
+14
+33
+240
+66
+58
+29
+70
+29
+85
+220
+23
+39
+92
+55
+15
+16
+219
+24
+-1
+101
+270
+458
+78
+77
+115
+409
+-1
+-1
+152
+192
+23
+163
+15
+34
+111
+592
+408
+71
+128
+190
+-1
+62
+-1
+-1
+81
+136
+31
+269
+14
+-1
+48
+-1
+35
+15
+-1
+64
+196
+117
+32
+48
+125
+64
+252
+-1
+75
+14
+-1
+60
+525
+22
+221
+71
+42
+59
+-1
+174
+152
+206
+136
+259
+162
+39
+-1
+-1
+37
+34
+34
+21
+267
+40
+214
+31
+20
+73
+34
+415
+38
+71
+49
+48
+150
+198
+-1
+-1
+66
+-1
+195
+153
+34
+-1
+135
+-1
+-1
+25
+103
+81
+15
+109
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize9.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize9.txt
new file mode 100644
index 0000000..ddd5375
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/howManyGenerations_5x5_300_600gen_k8popsize9.txt
@@ -0,0 +1,300 @@
+46
+71
+20
+138
+57
+14
+52
+118
+166
+36
+192
+237
+-1
+-1
+146
+90
+161
+41
+48
+-1
+-1
+425
+29
+-1
+51
+171
+-1
+240
+98
+35
+559
+-1
+44
+-1
+40
+25
+73
+290
+45
+112
+137
+17
+89
+68
+36
+40
+51
+248
+123
+70
+154
+117
+220
+163
+106
+39
+72
+190
+134
+266
+36
+28
+91
+16
+24
+119
+48
+-1
+86
+43
+76
+213
+55
+92
+19
+29
+295
+69
+437
+23
+109
+143
+129
+28
+26
+209
+87
+193
+66
+45
+424
+61
+-1
+45
+-1
+316
+41
+84
+373
+105
+35
+188
+39
+32
+56
+174
+47
+180
+152
+26
+249
+-1
+-1
+62
+45
+63
+259
+-1
+57
+119
+68
+14
+108
+64
+364
+70
+16
+315
+23
+188
+327
+25
+228
+58
+55
+235
+599
+-1
+113
+29
+181
+-1
+167
+178
+148
+25
+137
+77
+41
+143
+33
+-1
+-1
+28
+58
+73
+-1
+30
+225
+555
+31
+-1
+368
+17
+149
+64
+461
+-1
+30
+81
+-1
+37
+85
+32
+64
+-1
+52
+271
+186
+139
+84
+-1
+244
+156
+-1
+16
+204
+-1
+-1
+-1
+26
+87
+14
+89
+85
+87
+79
+56
+-1
+-1
+299
+-1
+45
+80
+204
+34
+45
+80
+43
+64
+158
+65
+311
+179
+296
+142
+66
+-1
+80
+402
+34
+175
+148
+174
+144
+-1
+40
+226
+60
+-1
+144
+-1
+321
+65
+26
+100
+448
+76
+14
+54
+20
+235
+218
+78
+74
+65
+22
+153
+-1
+322
+-1
+64
+169
+248
+67
+68
+42
+140
+207
+403
+86
+122
+-1
+-1
+180
+112
+80
+-1
+-1
+247
+199
+102
+-1
+-1
+35
+52
+28
+70
+-1
+51
+34
+60
+45
+79
+158
+71
+291
+-1
+-1
+29
+137
+176
+43
+176
+81
+172
+561
+58
+250
+133
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_1000_600gen_k8popsize1.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_1000_600gen_k8popsize1.txt
new file mode 100644
index 0000000..d6753f6
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_1000_600gen_k8popsize1.txt
@@ -0,0 +1,1000 @@
+316
+136
+21
+-1
+123
+-1
+123
+286
+516
+-1
+-1
+241
+110
+133
+242
+189
+495
+-1
+76
+80
+-1
+149
+44
+-1
+-1
+140
+-1
+126
+-1
+302
+271
+171
+-1
+-1
+39
+-1
+36
+138
+357
+142
+-1
+149
+350
+260
+322
+125
+66
+60
+-1
+29
+192
+-1
+140
+105
+134
+40
+57
+121
+233
+-1
+-1
+204
+-1
+-1
+222
+62
+108
+24
+42
+-1
+123
+143
+388
+354
+257
+192
+95
+-1
+241
+186
+482
+59
+62
+56
+52
+249
+-1
+123
+-1
+-1
+-1
+94
+102
+310
+94
+187
+174
+169
+230
+174
+530
+-1
+409
+242
+-1
+175
+-1
+283
+-1
+61
+-1
+177
+374
+437
+91
+207
+20
+219
+139
+53
+55
+148
+-1
+35
+199
+-1
+345
+-1
+128
+212
+384
+-1
+154
+20
+50
+155
+-1
+548
+197
+-1
+-1
+134
+25
+513
+105
+143
+237
+231
+-1
+234
+264
+113
+-1
+271
+-1
+320
+-1
+-1
+352
+319
+174
+-1
+-1
+142
+398
+-1
+332
+57
+425
+-1
+-1
+403
+406
+85
+145
+-1
+-1
+464
+129
+-1
+154
+197
+-1
+197
+295
+232
+-1
+-1
+141
+-1
+178
+380
+102
+38
+315
+161
+-1
+218
+127
+376
+211
+252
+140
+298
+-1
+146
+52
+100
+112
+333
+-1
+321
+402
+-1
+61
+22
+58
+193
+191
+-1
+18
+283
+-1
+169
+252
+230
+-1
+234
+31
+182
+88
+257
+166
+116
+367
+134
+104
+103
+-1
+-1
+363
+-1
+179
+33
+111
+-1
+199
+444
+186
+-1
+537
+427
+593
+218
+102
+197
+-1
+360
+83
+28
+39
+366
+21
+190
+402
+134
+56
+166
+-1
+317
+235
+175
+54
+273
+60
+186
+313
+175
+201
+234
+89
+199
+140
+457
+-1
+170
+178
+229
+351
+26
+169
+103
+-1
+263
+169
+119
+564
+461
+262
+156
+289
+174
+91
+109
+383
+262
+-1
+184
+38
+-1
+-1
+281
+297
+152
+196
+177
+-1
+124
+67
+283
+247
+-1
+65
+-1
+68
+355
+276
+120
+260
+222
+-1
+128
+261
+317
+111
+262
+-1
+262
+-1
+90
+203
+124
+171
+193
+-1
+-1
+153
+292
+367
+37
+142
+234
+208
+388
+340
+96
+335
+269
+429
+41
+175
+312
+309
+185
+-1
+269
+494
+384
+365
+-1
+33
+-1
+191
+587
+-1
+-1
+101
+197
+307
+506
+268
+109
+242
+460
+213
+76
+342
+115
+-1
+119
+-1
+-1
+134
+182
+367
+-1
+144
+75
+231
+-1
+119
+431
+338
+32
+-1
+-1
+147
+-1
+237
+128
+350
+196
+-1
+283
+308
+585
+-1
+236
+-1
+174
+395
+-1
+110
+189
+-1
+57
+318
+-1
+142
+398
+201
+-1
+-1
+466
+234
+82
+132
+69
+231
+-1
+54
+-1
+193
+202
+95
+-1
+-1
+367
+177
+144
+355
+57
+-1
+111
+150
+137
+146
+410
+149
+389
+-1
+161
+21
+260
+385
+215
+-1
+332
+147
+-1
+391
+-1
+91
+-1
+75
+270
+413
+-1
+-1
+-1
+150
+231
+427
+201
+-1
+191
+-1
+189
+-1
+25
+126
+379
+89
+78
+162
+-1
+429
+415
+204
+218
+59
+180
+-1
+-1
+586
+-1
+-1
+227
+475
+-1
+-1
+64
+218
+442
+128
+562
+198
+-1
+-1
+184
+207
+118
+329
+146
+343
+-1
+253
+199
+207
+97
+20
+233
+-1
+439
+18
+167
+146
+335
+-1
+82
+453
+-1
+-1
+69
+225
+-1
+-1
+204
+-1
+106
+186
+536
+143
+-1
+-1
+165
+-1
+224
+116
+191
+379
+284
+393
+-1
+94
+-1
+-1
+92
+-1
+128
+-1
+183
+-1
+196
+236
+-1
+92
+398
+291
+-1
+461
+-1
+-1
+-1
+283
+53
+114
+199
+143
+223
+577
+-1
+276
+126
+95
+133
+314
+120
+202
+291
+138
+369
+-1
+136
+228
+-1
+153
+367
+46
+137
+146
+48
+223
+-1
+227
+108
+143
+-1
+488
+89
+290
+-1
+135
+278
+-1
+-1
+262
+364
+-1
+292
+197
+-1
+-1
+-1
+235
+115
+176
+302
+-1
+247
+-1
+90
+59
+316
+250
+-1
+159
+224
+107
+-1
+-1
+52
+97
+-1
+164
+151
+87
+40
+279
+305
+175
+122
+-1
+255
+477
+64
+-1
+107
+233
+242
+112
+-1
+189
+-1
+78
+343
+-1
+-1
+473
+59
+-1
+128
+-1
+32
+375
+384
+-1
+350
+-1
+114
+285
+74
+100
+196
+384
+112
+155
+30
+-1
+200
+495
+-1
+222
+517
+469
+140
+-1
+-1
+464
+126
+137
+-1
+123
+63
+279
+-1
+89
+-1
+397
+121
+587
+300
+521
+-1
+107
+260
+-1
+282
+136
+496
+253
+498
+178
+173
+139
+362
+180
+167
+167
+62
+90
+148
+-1
+200
+159
+318
+-1
+-1
+177
+-1
+84
+179
+461
+371
+-1
+-1
+335
+-1
+230
+394
+570
+253
+-1
+378
+251
+80
+-1
+429
+177
+195
+-1
+287
+156
+165
+20
+57
+238
+48
+-1
+-1
+252
+354
+71
+444
+-1
+432
+-1
+236
+-1
+-1
+431
+-1
+-1
+332
+-1
+-1
+390
+519
+286
+249
+-1
+-1
+-1
+101
+-1
+-1
+70
+35
+65
+34
+-1
+23
+266
+-1
+-1
+161
+571
+338
+-1
+161
+-1
+-1
+92
+349
+102
+415
+261
+105
+143
+79
+146
+350
+561
+184
+174
+-1
+251
+-1
+-1
+138
+229
+209
+-1
+87
+335
+-1
+274
+-1
+48
+68
+187
+-1
+-1
+23
+352
+116
+86
+385
+516
+402
+-1
+158
+174
+283
+-1
+491
+110
+90
+-1
+247
+403
+-1
+-1
+97
+-1
+85
+267
+-1
+-1
+149
+302
+301
+-1
+202
+200
+-1
+-1
+395
+266
+-1
+-1
+229
+507
+512
+-1
+-1
+345
+210
+88
+136
+358
+479
+-1
+62
+49
+93
+121
+298
+176
+230
+-1
+97
+217
+-1
+-1
+240
+296
+210
+223
+-1
+275
+47
+22
+342
+143
+96
+366
+76
+235
+262
+89
+401
+-1
+-1
+191
+120
+-1
+-1
+-1
+157
+49
+-1
+207
+233
+267
+235
+-1
+75
+197
+105
+178
+119
+-1
+38
+384
+288
+34
+92
+336
+-1
+98
+24
+185
+201
+199
+77
+99
+-1
+143
+-1
+65
+-1
+209
+94
+231
+148
+-1
+-1
+-1
+-1
+-1
+25
+-1
+-1
+-1
+400
+440
+17
+84
+17
+-1
+-1
+57
+-1
+270
+-1
+20
+589
+150
+242
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize10.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize10.txt
new file mode 100644
index 0000000..1b15f4e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize10.txt
@@ -0,0 +1,300 @@
+29
+134
+63
+138
+26
+-1
+44
+-1
+214
+-1
+206
+83
+-1
+81
+33
+113
+42
+53
+17
+534
+72
+66
+113
+295
+209
+51
+21
+-1
+365
+59
+526
+222
+428
+223
+31
+260
+-1
+-1
+64
+324
+33
+182
+75
+46
+201
+31
+175
+74
+56
+18
+174
+66
+-1
+214
+25
+-1
+18
+113
+-1
+26
+38
+30
+58
+294
+-1
+48
+105
+137
+96
+34
+14
+90
+131
+364
+121
+-1
+198
+337
+37
+23
+16
+82
+113
+35
+-1
+128
+236
+235
+101
+276
+128
+47
+246
+63
+59
+82
+-1
+70
+147
+70
+32
+-1
+-1
+18
+61
+35
+57
+78
+33
+467
+125
+59
+-1
+119
+64
+185
+-1
+60
+35
+54
+147
+-1
+188
+349
+158
+146
+171
+28
+237
+27
+-1
+250
+529
+180
+47
+99
+387
+53
+19
+-1
+28
+298
+206
+41
+63
+19
+82
+202
+571
+60
+28
+47
+143
+230
+40
+-1
+149
+188
+179
+-1
+148
+70
+46
+179
+33
+30
+182
+17
+66
+29
+39
+193
+15
+73
+33
+96
+58
+148
+56
+105
+67
+61
+101
+-1
+49
+24
+152
+36
+21
+-1
+17
+14
+-1
+20
+27
+43
+119
+332
+73
+106
+27
+252
+143
+415
+28
+44
+147
+469
+303
+166
+189
+71
+-1
+105
+-1
+190
+88
+41
+-1
+27
+185
+116
+16
+103
+190
+26
+223
+412
+373
+26
+-1
+365
+139
+80
+300
+256
+-1
+45
+280
+51
+91
+15
+46
+91
+256
+-1
+53
+168
+188
+209
+-1
+38
+-1
+188
+237
+66
+-1
+46
+30
+-1
+184
+23
+82
+37
+25
+123
+84
+257
+195
+93
+-1
+14
+75
+522
+15
+-1
+83
+254
+213
+98
+115
+262
+200
+118
+100
+473
+60
+-1
+206
+15
+137
+-1
+268
+36
+68
+130
+-1
+-1
+75
+337
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize11.txt
new file mode 100644
index 0000000..aa9075d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize11.txt
@@ -0,0 +1,300 @@
+51
+155
+52
+102
+34
+74
+-1
+177
+52
+112
+-1
+119
+50
+115
+220
+136
+-1
+-1
+58
+18
+-1
+22
+96
+42
+22
+45
+144
+241
+75
+-1
+149
+14
+-1
+15
+452
+-1
+213
+93
+51
+-1
+-1
+41
+-1
+57
+-1
+-1
+85
+23
+439
+106
+45
+-1
+19
+33
+21
+29
+53
+15
+18
+36
+135
+-1
+43
+77
+16
+-1
+498
+20
+-1
+66
+105
+36
+109
+17
+190
+102
+231
+16
+132
+-1
+101
+515
+-1
+168
+230
+53
+128
+36
+95
+102
+61
+69
+42
+65
+72
+382
+42
+99
+34
+24
+80
+43
+-1
+419
+105
+219
+125
+-1
+108
+31
+37
+-1
+240
+77
+315
+23
+74
+-1
+58
+-1
+47
+204
+34
+63
+83
+249
+17
+67
+163
+22
+42
+47
+-1
+28
+142
+-1
+64
+207
+-1
+75
+81
+48
+148
+30
+44
+-1
+99
+19
+-1
+140
+50
+76
+185
+30
+-1
+99
+23
+67
+188
+96
+431
+116
+50
+48
+183
+-1
+303
+565
+60
+76
+27
+-1
+-1
+16
+36
+224
+78
+44
+50
+-1
+-1
+21
+144
+198
+189
+31
+281
+-1
+28
+-1
+172
+38
+40
+-1
+103
+49
+290
+242
+130
+-1
+-1
+72
+-1
+61
+36
+38
+250
+75
+-1
+-1
+-1
+33
+32
+46
+-1
+47
+26
+250
+82
+66
+74
+14
+47
+60
+133
+17
+98
+52
+-1
+-1
+135
+16
+25
+18
+-1
+14
+66
+-1
+20
+15
+159
+363
+246
+334
+190
+39
+31
+73
+-1
+33
+50
+330
+229
+-1
+15
+52
+-1
+91
+62
+547
+54
+102
+33
+58
+78
+23
+238
+183
+104
+-1
+-1
+24
+-1
+33
+116
+392
+-1
+156
+14
+178
+160
+-1
+161
+106
+326
+17
+65
+34
+254
+38
+-1
+54
+22
+216
+37
+168
+99
+47
+229
+342
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize12.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize12.txt
new file mode 100644
index 0000000..6ef0fef
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize12.txt
@@ -0,0 +1,300 @@
+377
+247
+-1
+-1
+45
+324
+348
+416
+51
+29
+63
+34
+147
+154
+30
+261
+-1
+51
+56
+198
+101
+35
+266
+107
+218
+-1
+85
+-1
+82
+231
+23
+245
+73
+65
+65
+455
+74
+14
+-1
+25
+124
+24
+-1
+200
+-1
+-1
+111
+186
+42
+180
+65
+-1
+73
+269
+62
+292
+114
+49
+88
+232
+27
+114
+-1
+125
+-1
+357
+60
+65
+164
+76
+-1
+21
+16
+367
+105
+20
+254
+70
+-1
+118
+-1
+43
+35
+-1
+14
+17
+116
+80
+40
+17
+28
+119
+23
+76
+-1
+102
+401
+89
+186
+30
+147
+52
+26
+81
+17
+16
+61
+120
+157
+358
+152
+311
+245
+-1
+87
+24
+-1
+43
+60
+67
+122
+88
+169
+35
+-1
+67
+16
+140
+75
+31
+-1
+186
+-1
+133
+59
+28
+36
+38
+88
+63
+28
+-1
+-1
+-1
+169
+23
+68
+56
+104
+-1
+18
+46
+48
+-1
+125
+24
+124
+182
+52
+276
+-1
+-1
+-1
+-1
+392
+93
+18
+88
+15
+51
+410
+210
+43
+102
+116
+54
+413
+50
+86
+-1
+56
+213
+59
+199
+42
+129
+-1
+-1
+67
+67
+35
+14
+31
+95
+45
+108
+79
+41
+93
+61
+44
+35
+-1
+75
+-1
+18
+81
+97
+22
+-1
+73
+147
+167
+69
+486
+-1
+175
+557
+32
+16
+26
+206
+66
+14
+73
+156
+-1
+26
+146
+21
+19
+74
+-1
+64
+273
+144
+-1
+49
+298
+46
+258
+37
+496
+75
+139
+519
+150
+82
+70
+87
+131
+241
+93
+-1
+182
+308
+52
+19
+59
+16
+76
+97
+116
+-1
+36
+-1
+111
+162
+-1
+140
+413
+370
+322
+64
+-1
+25
+47
+-1
+133
+-1
+205
+95
+94
+102
+14
+74
+47
+33
+-1
+26
+39
+48
+61
+134
+25
+-1
+232
+-1
+377
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize13.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize13.txt
new file mode 100644
index 0000000..a69fe39
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize13.txt
@@ -0,0 +1,300 @@
+25
+43
+189
+440
+527
+31
+106
+53
+91
+48
+109
+-1
+433
+97
+-1
+111
+-1
+65
+17
+25
+66
+46
+49
+61
+94
+189
+104
+222
+402
+96
+62
+-1
+28
+226
+193
+203
+189
+27
+120
+449
+123
+39
+112
+65
+18
+60
+44
+192
+29
+279
+41
+-1
+41
+44
+64
+32
+-1
+109
+28
+142
+96
+261
+-1
+28
+66
+145
+71
+94
+87
+72
+-1
+96
+-1
+49
+105
+490
+34
+-1
+81
+14
+-1
+445
+143
+277
+185
+14
+185
+33
+468
+190
+71
+190
+121
+58
+58
+76
+51
+-1
+38
+395
+75
+-1
+300
+23
+96
+-1
+42
+171
+62
+109
+24
+340
+-1
+23
+113
+135
+125
+51
+93
+271
+212
+38
+-1
+43
+114
+67
+190
+-1
+37
+-1
+368
+48
+23
+201
+-1
+104
+49
+-1
+35
+160
+527
+50
+314
+24
+71
+464
+34
+413
+74
+-1
+51
+-1
+38
+21
+86
+44
+71
+114
+60
+17
+112
+178
+177
+98
+67
+23
+240
+25
+-1
+132
+-1
+-1
+233
+14
+76
+125
+76
+152
+21
+36
+130
+68
+58
+217
+206
+287
+110
+53
+170
+20
+78
+193
+95
+208
+20
+507
+65
+187
+-1
+80
+122
+33
+19
+180
+259
+-1
+161
+121
+142
+47
+334
+-1
+-1
+-1
+65
+16
+17
+132
+67
+130
+126
+-1
+-1
+31
+69
+39
+47
+27
+74
+97
+69
+-1
+73
+22
+71
+43
+148
+385
+46
+38
+500
+28
+16
+188
+64
+14
+45
+27
+193
+-1
+-1
+34
+109
+404
+46
+103
+99
+68
+63
+110
+59
+43
+81
+105
+47
+-1
+-1
+34
+58
+69
+109
+40
+114
+50
+30
+123
+373
+149
+92
+120
+127
+76
+24
+98
+14
+67
+84
+147
+178
+52
+43
+109
+35
+326
+187
+-1
+346
+-1
+139
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize14.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize14.txt
new file mode 100644
index 0000000..9fd40b0
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize14.txt
@@ -0,0 +1,300 @@
+15
+16
+141
+165
+40
+177
+14
+-1
+107
+41
+-1
+-1
+92
+82
+33
+58
+114
+166
+91
+52
+151
+-1
+53
+262
+40
+42
+-1
+15
+591
+66
+-1
+54
+95
+93
+32
+16
+77
+54
+44
+89
+24
+146
+26
+181
+38
+59
+37
+-1
+-1
+146
+226
+571
+26
+202
+168
+148
+80
+42
+148
+-1
+44
+162
+-1
+97
+85
+61
+76
+-1
+26
+-1
+217
+269
+393
+46
+-1
+85
+132
+115
+476
+27
+86
+22
+-1
+-1
+58
+68
+-1
+54
+97
+138
+36
+109
+31
+183
+71
+33
+23
+332
+96
+90
+97
+15
+24
+88
+18
+33
+34
+188
+-1
+14
+308
+-1
+32
+15
+90
+73
+38
+-1
+-1
+74
+57
+204
+42
+65
+44
+-1
+49
+81
+22
+323
+14
+76
+43
+20
+39
+24
+131
+19
+192
+514
+120
+20
+589
+390
+-1
+15
+22
+95
+123
+32
+-1
+189
+50
+-1
+-1
+138
+84
+125
+26
+46
+-1
+155
+177
+114
+46
+109
+-1
+23
+-1
+20
+15
+363
+104
+60
+41
+183
+51
+145
+308
+-1
+22
+31
+-1
+-1
+16
+54
+206
+135
+276
+158
+51
+-1
+63
+40
+74
+150
+76
+209
+252
+-1
+29
+307
+26
+26
+306
+108
+41
+-1
+23
+34
+36
+-1
+36
+57
+43
+79
+126
+38
+99
+-1
+495
+69
+21
+23
+118
+15
+-1
+-1
+21
+70
+63
+-1
+108
+189
+36
+-1
+254
+-1
+300
+187
+202
+48
+64
+225
+-1
+22
+42
+39
+142
+69
+61
+28
+202
+142
+217
+187
+-1
+-1
+585
+53
+402
+83
+265
+65
+-1
+27
+-1
+102
+30
+42
+130
+117
+93
+31
+59
+38
+45
+111
+40
+-1
+300
+119
+110
+26
+19
+92
+403
+41
+79
+259
+119
+14
+122
+44
+40
+70
+44
+66
+235
+305
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize2.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize2.txt
new file mode 100644
index 0000000..5aaceec
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize2.txt
@@ -0,0 +1,300 @@
+88
+74
+-1
+-1
+173
+-1
+204
+100
+28
+-1
+236
+69
+-1
+199
+70
+142
+197
+28
+268
+170
+-1
+197
+50
+96
+169
+-1
+-1
+121
+58
+216
+92
+258
+-1
+93
+-1
+101
+49
+164
+243
+231
+56
+289
+54
+-1
+17
+129
+150
+140
+28
+59
+250
+73
+348
+258
+140
+129
+-1
+96
+29
+-1
+19
+75
+-1
+75
+-1
+171
+234
+83
+237
+85
+81
+-1
+-1
+64
+18
+229
+-1
+356
+344
+83
+142
+141
+58
+111
+64
+277
+190
+45
+54
+42
+110
+131
+310
+220
+217
+176
+37
+245
+44
+48
+-1
+86
+159
+233
+471
+25
+-1
+232
+242
+-1
+144
+49
+230
+-1
+57
+-1
+24
+105
+345
+312
+73
+557
+38
+-1
+131
+324
+44
+-1
+392
+72
+47
+-1
+28
+126
+-1
+122
+239
+-1
+-1
+46
+35
+148
+74
+103
+85
+239
+71
+256
+-1
+-1
+249
+72
+39
+211
+191
+113
+75
+105
+-1
+-1
+131
+410
+-1
+48
+158
+39
+90
+109
+-1
+82
+-1
+93
+236
+115
+249
+188
+211
+68
+-1
+-1
+102
+131
+75
+143
+77
+-1
+-1
+63
+315
+-1
+206
+216
+35
+-1
+49
+33
+257
+312
+69
+342
+265
+153
+244
+-1
+114
+444
+591
+107
+169
+97
+429
+475
+47
+-1
+52
+297
+128
+127
+98
+-1
+145
+178
+15
+284
+167
+-1
+242
+82
+53
+172
+-1
+106
+132
+127
+70
+184
+-1
+241
+27
+83
+-1
+206
+68
+201
+211
+23
+63
+64
+-1
+127
+146
+355
+61
+243
+-1
+198
+74
+24
+-1
+30
+148
+111
+310
+52
+-1
+242
+-1
+39
+341
+-1
+73
+341
+-1
+53
+152
+-1
+-1
+72
+478
+-1
+-1
+282
+201
+270
+63
+144
+-1
+418
+48
+350
+269
+-1
+54
+119
+547
+38
+143
+264
+-1
+499
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize3.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize3.txt
new file mode 100644
index 0000000..77c483b
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize3.txt
@@ -0,0 +1,300 @@
+209
+238
+240
+158
+76
+122
+-1
+-1
+86
+237
+105
+173
+104
+43
+38
+32
+97
+91
+25
+-1
+437
+-1
+47
+-1
+41
+-1
+63
+84
+30
+173
+237
+340
+17
+31
+128
+353
+298
+-1
+-1
+-1
+73
+111
+351
+-1
+282
+30
+167
+315
+133
+-1
+149
+119
+210
+50
+225
+304
+19
+-1
+149
+411
+69
+32
+223
+84
+134
+64
+-1
+75
+187
+276
+105
+118
+173
+-1
+146
+41
+41
+-1
+60
+-1
+206
+67
+-1
+73
+192
+244
+-1
+84
+42
+97
+95
+14
+-1
+104
+245
+149
+232
+213
+157
+-1
+48
+106
+90
+94
+91
+16
+102
+42
+83
+111
+250
+82
+469
+105
+133
+134
+57
+-1
+-1
+-1
+261
+53
+87
+101
+242
+74
+278
+145
+146
+84
+55
+98
+73
+-1
+125
+215
+219
+270
+231
+89
+459
+397
+153
+187
+14
+43
+25
+155
+54
+-1
+53
+84
+16
+229
+68
+-1
+151
+329
+-1
+126
+54
+48
+14
+372
+56
+-1
+33
+32
+135
+249
+285
+129
+81
+-1
+154
+32
+104
+-1
+522
+444
+46
+21
+-1
+86
+-1
+47
+227
+101
+-1
+158
+18
+-1
+86
+133
+-1
+295
+34
+75
+106
+18
+23
+-1
+190
+-1
+161
+147
+57
+109
+76
+109
+242
+90
+53
+-1
+152
+237
+41
+285
+242
+320
+115
+100
+148
+-1
+59
+-1
+176
+127
+75
+-1
+127
+197
+47
+127
+62
+221
+-1
+308
+255
+103
+248
+-1
+-1
+76
+-1
+204
+209
+179
+62
+141
+74
+52
+215
+321
+82
+27
+425
+433
+88
+389
+224
+-1
+247
+14
+27
+145
+287
+52
+67
+50
+251
+43
+164
+-1
+-1
+354
+-1
+47
+61
+74
+173
+197
+161
+78
+509
+222
+-1
+115
+313
+481
+38
+105
+-1
+-1
+243
+-1
+-1
+16
+192
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize4.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize4.txt
new file mode 100644
index 0000000..0857f29
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize4.txt
@@ -0,0 +1,300 @@
+45
+167
+182
+73
+-1
+-1
+18
+38
+70
+145
+50
+-1
+17
+15
+37
+388
+289
+176
+-1
+197
+55
+80
+132
+-1
+30
+-1
+82
+317
+62
+165
+165
+-1
+191
+-1
+156
+275
+34
+192
+81
+82
+93
+59
+153
+-1
+41
+88
+82
+160
+55
+182
+-1
+55
+417
+-1
+-1
+143
+52
+23
+17
+86
+-1
+20
+-1
+-1
+542
+158
+44
+14
+124
+69
+84
+41
+-1
+116
+139
+90
+69
+161
+52
+121
+133
+220
+347
+-1
+67
+390
+318
+40
+54
+40
+-1
+172
+175
+207
+136
+17
+28
+-1
+28
+68
+82
+15
+237
+25
+-1
+115
+86
+49
+402
+163
+80
+97
+229
+16
+90
+111
+176
+112
+14
+276
+47
+48
+94
+146
+137
+30
+138
+-1
+35
+207
+-1
+20
+23
+112
+316
+133
+52
+43
+44
+70
+16
+147
+37
+106
+127
+568
+190
+205
+47
+-1
+20
+43
+37
+63
+-1
+16
+429
+72
+89
+-1
+202
+169
+275
+107
+118
+119
+221
+48
+87
+30
+-1
+53
+-1
+23
+194
+164
+-1
+15
+94
+90
+213
+142
+308
+251
+23
+198
+78
+254
+382
+-1
+302
+-1
+66
+44
+63
+80
+101
+134
+377
+54
+16
+-1
+119
+55
+191
+-1
+235
+177
+-1
+30
+105
+147
+184
+79
+-1
+45
+82
+181
+359
+55
+40
+44
+47
+60
+45
+72
+248
+-1
+-1
+226
+112
+76
+107
+165
+-1
+113
+-1
+-1
+94
+588
+-1
+526
+153
+160
+160
+147
+139
+-1
+140
+72
+15
+-1
+51
+-1
+40
+54
+28
+200
+76
+-1
+383
+270
+141
+202
+418
+106
+189
+27
+113
+-1
+159
+224
+-1
+-1
+-1
+215
+117
+81
+349
+243
+75
+58
+181
+133
+19
+50
+17
+16
+249
+56
+36
+17
+211
+38
+210
+285
+199
+417
+104
+228
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize5.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize5.txt
new file mode 100644
index 0000000..05f4538
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize5.txt
@@ -0,0 +1,300 @@
+39
+48
+46
+121
+103
+67
+35
+184
+62
+71
+84
+132
+343
+-1
+-1
+40
+95
+216
+97
+355
+261
+45
+39
+16
+-1
+-1
+409
+38
+186
+213
+36
+425
+128
+90
+-1
+-1
+126
+57
+39
+24
+140
+-1
+208
+-1
+-1
+122
+21
+-1
+56
+53
+103
+33
+182
+78
+-1
+84
+229
+110
+32
+319
+288
+307
+535
+51
+98
+151
+43
+188
+212
+138
+-1
+49
+109
+36
+223
+310
+155
+67
+104
+137
+213
+35
+134
+-1
+100
+120
+56
+80
+162
+128
+126
+451
+54
+115
+121
+17
+191
+308
+339
+41
+16
+102
+41
+342
+98
+19
+42
+79
+282
+-1
+50
+140
+119
+85
+14
+26
+81
+500
+34
+136
+247
+-1
+140
+151
+548
+137
+43
+16
+63
+-1
+27
+-1
+86
+31
+118
+334
+215
+154
+105
+48
+247
+243
+45
+40
+136
+-1
+188
+-1
+75
+189
+-1
+19
+26
+28
+23
+47
+57
+187
+32
+44
+38
+280
+69
+407
+48
+198
+97
+192
+15
+34
+-1
+243
+29
+62
+21
+38
+74
+136
+396
+198
+326
+201
+199
+-1
+132
+25
+197
+16
+68
+15
+119
+72
+22
+150
+41
+197
+-1
+54
+62
+-1
+16
+-1
+15
+22
+35
+75
+85
+-1
+133
+141
+-1
+26
+144
+191
+58
+85
+106
+46
+230
+-1
+19
+220
+28
+-1
+108
+346
+-1
+23
+292
+37
+26
+40
+14
+57
+206
+22
+-1
+43
+193
+60
+93
+78
+53
+83
+-1
+43
+-1
+78
+103
+159
+16
+154
+206
+-1
+128
+380
+245
+-1
+15
+-1
+166
+263
+121
+-1
+43
+-1
+14
+167
+-1
+-1
+14
+153
+39
+48
+-1
+200
+37
+38
+302
+76
+448
+35
+55
+114
+-1
+194
+28
+-1
+49
+168
+56
+191
+461
+74
+169
+392
+243
+279
+511
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize6.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize6.txt
new file mode 100644
index 0000000..ed94a53
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize6.txt
@@ -0,0 +1,300 @@
+24
+19
+51
+332
+-1
+218
+25
+-1
+58
+102
+87
+-1
+58
+220
+-1
+333
+41
+45
+61
+179
+410
+58
+102
+-1
+57
+217
+436
+66
+46
+294
+497
+87
+24
+-1
+68
+227
+39
+220
+92
+16
+221
+22
+-1
+218
+31
+38
+345
+-1
+45
+44
+42
+429
+22
+81
+-1
+75
+89
+233
+64
+37
+56
+71
+128
+86
+39
+35
+257
+23
+165
+53
+64
+104
+-1
+110
+21
+87
+-1
+39
+105
+31
+230
+-1
+259
+-1
+-1
+76
+-1
+78
+335
+228
+-1
+29
+-1
+185
+29
+182
+157
+49
+525
+31
+43
+570
+69
+229
+95
+233
+189
+46
+31
+92
+107
+25
+-1
+65
+196
+20
+-1
+78
+116
+162
+186
+48
+28
+44
+202
+272
+-1
+186
+129
+30
+40
+166
+77
+-1
+32
+155
+39
+478
+-1
+34
+188
+102
+-1
+-1
+24
+14
+197
+-1
+80
+40
+-1
+60
+134
+28
+67
+26
+-1
+92
+72
+61
+-1
+94
+141
+154
+-1
+-1
+93
+198
+187
+310
+77
+286
+139
+43
+486
+100
+162
+220
+62
+272
+362
+116
+230
+95
+15
+186
+107
+58
+15
+110
+-1
+14
+22
+-1
+-1
+194
+20
+30
+-1
+74
+182
+186
+-1
+98
+47
+-1
+14
+91
+130
+111
+18
+-1
+169
+44
+18
+95
+-1
+61
+228
+76
+46
+105
+202
+17
+43
+222
+16
+102
+46
+-1
+-1
+112
+155
+184
+214
+43
+207
+245
+116
+144
+94
+135
+28
+-1
+64
+76
+90
+43
+174
+-1
+14
+143
+98
+50
+44
+-1
+28
+37
+-1
+94
+207
+-1
+95
+175
+-1
+-1
+15
+83
+57
+150
+356
+448
+52
+36
+200
+98
+24
+18
+34
+197
+48
+14
+76
+24
+28
+194
+-1
+-1
+78
+293
+141
+261
+243
+74
+130
+118
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize7.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize7.txt
new file mode 100644
index 0000000..396e411
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize7.txt
@@ -0,0 +1,300 @@
+42
+21
+76
+139
+59
+181
+63
+244
+35
+57
+193
+-1
+22
+-1
+-1
+217
+288
+55
+71
+204
+-1
+251
+62
+-1
+82
+-1
+224
+98
+172
+36
+589
+-1
+203
+22
+30
+93
+-1
+79
+233
+121
+55
+44
+54
+174
+538
+-1
+127
+-1
+61
+219
+-1
+193
+82
+-1
+-1
+-1
+244
+141
+139
+37
+23
+-1
+262
+87
+255
+-1
+205
+27
+42
+77
+-1
+156
+15
+28
+-1
+142
+-1
+248
+45
+30
+-1
+355
+34
+-1
+393
+40
+20
+187
+177
+24
+-1
+27
+-1
+347
+14
+-1
+-1
+349
+95
+164
+101
+-1
+-1
+218
+77
+37
+-1
+-1
+475
+103
+186
+475
+110
+-1
+36
+154
+155
+122
+95
+-1
+140
+164
+187
+185
+153
+-1
+85
+255
+137
+249
+134
+152
+498
+18
+24
+172
+34
+171
+-1
+-1
+76
+42
+14
+-1
+-1
+-1
+295
+40
+141
+-1
+178
+177
+35
+167
+-1
+60
+-1
+79
+162
+146
+149
+198
+53
+387
+-1
+65
+-1
+-1
+-1
+122
+65
+100
+38
+49
+388
+179
+266
+-1
+48
+504
+154
+47
+-1
+42
+-1
+-1
+38
+135
+90
+122
+-1
+168
+65
+92
+65
+42
+218
+47
+177
+22
+-1
+124
+-1
+-1
+236
+60
+132
+105
+83
+-1
+119
+-1
+35
+38
+21
+-1
+120
+16
+255
+-1
+-1
+143
+-1
+207
+49
+32
+141
+525
+88
+-1
+67
+309
+-1
+-1
+236
+200
+75
+-1
+191
+64
+-1
+72
+262
+61
+19
+-1
+365
+111
+-1
+229
+173
+100
+112
+91
+-1
+70
+240
+66
+14
+122
+137
+196
+151
+202
+176
+-1
+44
+49
+51
+143
+57
+162
+-1
+241
+21
+169
+106
+20
+-1
+210
+65
+127
+472
+97
+-1
+-1
+-1
+63
+54
+109
+143
+147
+49
+38
+20
+171
+58
+258
+215
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize8.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize8.txt
new file mode 100644
index 0000000..cf940ac
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize8.txt
@@ -0,0 +1,300 @@
+62
+397
+37
+25
+-1
+-1
+40
+170
+169
+20
+76
+74
+61
+187
+174
+-1
+167
+228
+28
+-1
+14
+86
+256
+27
+-1
+540
+77
+14
+-1
+152
+174
+-1
+390
+43
+77
+91
+20
+52
+151
+228
+-1
+25
+-1
+-1
+27
+-1
+56
+336
+76
+63
+118
+64
+508
+118
+140
+-1
+60
+-1
+-1
+95
+84
+67
+90
+59
+243
+191
+16
+34
+242
+41
+91
+112
+109
+47
+15
+132
+251
+35
+69
+55
+95
+47
+97
+164
+15
+394
+219
+432
+374
+328
+15
+-1
+21
+64
+194
+39
+59
+223
+15
+14
+102
+104
+84
+273
+101
+49
+61
+99
+-1
+41
+51
+37
+-1
+115
+44
+329
+425
+51
+165
+41
+132
+88
+15
+-1
+90
+139
+24
+36
+31
+185
+254
+52
+-1
+161
+116
+66
+238
+194
+193
+60
+90
+-1
+25
+64
+135
+465
+96
+-1
+182
+588
+218
+190
+73
+-1
+24
+210
+18
+-1
+53
+335
+63
+-1
+-1
+313
+116
+71
+14
+85
+74
+-1
+31
+-1
+53
+108
+39
+35
+82
+-1
+62
+312
+65
+118
+14
+33
+240
+66
+58
+29
+70
+29
+85
+220
+23
+39
+92
+55
+15
+16
+219
+24
+-1
+101
+270
+458
+78
+77
+115
+409
+-1
+-1
+152
+192
+23
+163
+15
+34
+111
+592
+408
+71
+128
+190
+-1
+62
+-1
+-1
+81
+136
+31
+269
+14
+-1
+48
+-1
+35
+15
+-1
+64
+196
+117
+32
+48
+125
+64
+252
+-1
+75
+14
+-1
+60
+525
+22
+221
+71
+42
+59
+-1
+174
+152
+206
+136
+259
+162
+39
+-1
+-1
+37
+34
+34
+21
+267
+40
+214
+31
+20
+73
+34
+415
+38
+71
+49
+48
+150
+198
+-1
+-1
+66
+-1
+195
+153
+34
+-1
+135
+-1
+-1
+25
+103
+81
+15
+109
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize9.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize9.txt
new file mode 100644
index 0000000..ddd5375
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize9.txt
@@ -0,0 +1,300 @@
+46
+71
+20
+138
+57
+14
+52
+118
+166
+36
+192
+237
+-1
+-1
+146
+90
+161
+41
+48
+-1
+-1
+425
+29
+-1
+51
+171
+-1
+240
+98
+35
+559
+-1
+44
+-1
+40
+25
+73
+290
+45
+112
+137
+17
+89
+68
+36
+40
+51
+248
+123
+70
+154
+117
+220
+163
+106
+39
+72
+190
+134
+266
+36
+28
+91
+16
+24
+119
+48
+-1
+86
+43
+76
+213
+55
+92
+19
+29
+295
+69
+437
+23
+109
+143
+129
+28
+26
+209
+87
+193
+66
+45
+424
+61
+-1
+45
+-1
+316
+41
+84
+373
+105
+35
+188
+39
+32
+56
+174
+47
+180
+152
+26
+249
+-1
+-1
+62
+45
+63
+259
+-1
+57
+119
+68
+14
+108
+64
+364
+70
+16
+315
+23
+188
+327
+25
+228
+58
+55
+235
+599
+-1
+113
+29
+181
+-1
+167
+178
+148
+25
+137
+77
+41
+143
+33
+-1
+-1
+28
+58
+73
+-1
+30
+225
+555
+31
+-1
+368
+17
+149
+64
+461
+-1
+30
+81
+-1
+37
+85
+32
+64
+-1
+52
+271
+186
+139
+84
+-1
+244
+156
+-1
+16
+204
+-1
+-1
+-1
+26
+87
+14
+89
+85
+87
+79
+56
+-1
+-1
+299
+-1
+45
+80
+204
+34
+45
+80
+43
+64
+158
+65
+311
+179
+296
+142
+66
+-1
+80
+402
+34
+175
+148
+174
+144
+-1
+40
+226
+60
+-1
+144
+-1
+321
+65
+26
+100
+448
+76
+14
+54
+20
+235
+218
+78
+74
+65
+22
+153
+-1
+322
+-1
+64
+169
+248
+67
+68
+42
+140
+207
+403
+86
+122
+-1
+-1
+180
+112
+80
+-1
+-1
+247
+199
+102
+-1
+-1
+35
+52
+28
+70
+-1
+51
+34
+60
+45
+79
+158
+71
+291
+-1
+-1
+29
+137
+176
+43
+176
+81
+172
+561
+58
+250
+133
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/docker-compose.yml b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/docker-compose.yml
new file mode 100644
index 0000000..107fc50
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/docker-compose.yml
@@ -0,0 +1,21 @@
+services:
+ major-miner:
+ build: .
+ container_name: major-miner
+ environment:
+ CORE_PERCENTAGE: 90
+ MAX_MUTATION_TRIALS: 30
+ PROB_EXTEND_TO_FREE_NEIGHBOR: 0.3
+ MAX_TOTAL: 1000
+ MAX_GENERATIONS: 600
+ PROB_REMOVE_REDUNDANCY: 0.01
+ GRID_M: 5
+ GRID_N: 5
+ K_GRAPH: 8
+ POPSIZE: 6
+ PROB_STEPS: 20
+
+ volumes:
+ - type: bind
+ source: ./out
+ target: /app/out
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/evolution_dockerized.py b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/evolution_dockerized.py
new file mode 100644
index 0000000..2efaa8c
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/evolution_dockerized.py
@@ -0,0 +1,146 @@
+# Move this file to src/solver to start
+# Disable logger!
+
+import logging
+import multiprocessing
+import os
+import shutil
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+import numpy as np
+from src.drawing.draw import DrawEmbedding
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+################################# Params #######################################
+
+max_total = int(os.getenv('MAX_TOTAL', 300))
+max_generations = int(os.getenv('MAX_GENERATIONS', 600))
+remove_redundancy_probability = float(os.getenv('PROB_REMOVE_REDUNDANCY', 0.01))
+
+# Chimera graph
+m = int(os.getenv('GRID_M', 5)) # grid size
+n = int(os.getenv('GRID_N', 5)) # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+# d = DrawEmbedding(m, n, t)
+
+
+def different_params():
+ # # --- Clear
+ # try:
+ # shutil.rmtree('./out/')
+ # except FileNotFoundError:
+ # pass
+ # os.mkdir('./out')
+
+ prob_steps = int(os.getenv('PROB_STEPS', 20))
+ for prob in np.linspace(0.0, 1.0, num=prob_steps):
+ prob = round(prob, 2)
+ print(f'Started probability {prob}')
+ graph_number = int(os.getenv('K_GRAPH', 8))
+ graph = TestGraph.k(graph_number)
+ start_time = time.time()
+ start_multiprocessing((graph, prob), f'k{graph_number}prob{prob}')
+ duration = time.time() - start_time
+ print(f'Duration for probability {prob}: {duration} s')
+
+
+def start_multiprocessing(plot_params, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 75)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, plot_params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/howManyGenerations_{m}x{n}_{max_total}_{max_generations}gen_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(plot_params, j) -> int:
+ solver = EmbeddingSolver(plot_params[0], m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver, plot_params)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ # save_embedding(*solver.get_embedding(), d, f'{j}-{i}final', plot_params,
+ # title=f'Generation {i} (final with redundancy removed)')
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver, plot_params) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ evo_params = EvolutionParams(
+ population_size=int(os.getenv('POPSIZE', 6)),
+ max_mutation_trials=int(os.getenv('MAX_MUTATION_TRIALS', 30)),
+ mutation_extend_to_free_neighbors_probability=plot_params[1]
+ )
+
+ child = solver.generate_population_and_select(evo_params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+# def save_embedding(nodes: set[int], edges: set[tuple[int, int, int]],
+# mapping_G_to_H, d: DrawEmbedding, name: str, plot_params, title=''):
+# logger.info('')
+# logger.info('🎈 Current embedding')
+# logger.info(f'edges: {edges}')
+# logger.info(f'mapping_G_to_H: {mapping_G_to_H}')
+
+# d.draw_whole_embedding_step(nodes, edges, mapping_G_to_H, title=title)
+
+# folder_path = f'./out/popsize{plot_params[1]}'
+# if not os.path.exists(folder_path):
+# os.mkdir(folder_path)
+# d.save_and_clear(os.path.join(folder_path, f'{name}.svg'))
+
+
+if __name__ == "__main__":
+ different_params()
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.0.txt
new file mode 100644
index 0000000..8b47c05
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.0.txt
@@ -0,0 +1,20 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.02.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.02.txt
new file mode 100644
index 0000000..8b47c05
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.02.txt
@@ -0,0 +1,20 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.04.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.04.txt
new file mode 100644
index 0000000..6ff6aa4
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.04.txt
@@ -0,0 +1,20 @@
+-1
+-1
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.07.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.07.txt
new file mode 100644
index 0000000..167a3e3
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.07.txt
@@ -0,0 +1,20 @@
+30
+37
+-1
+-1
+66
+-1
+-1
+-1
+104
+-1
+40
+46
+-1
+139
+48
+58
+91
+185
+350
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.09.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.09.txt
new file mode 100644
index 0000000..7263e13
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.09.txt
@@ -0,0 +1,20 @@
+18
+39
+57
+60
+87
+69
+28
+86
+-1
+-1
+103
+109
+30
+-1
+-1
+105
+109
+159
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.11.txt
new file mode 100644
index 0000000..d4d2107
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.11.txt
@@ -0,0 +1,20 @@
+-1
+37
+36
+70
+31
+19
+169
+46
+30
+73
+68
+125
+-1
+176
+42
+175
+55
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.13.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.13.txt
new file mode 100644
index 0000000..6c0af99
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.13.txt
@@ -0,0 +1,20 @@
+24
+36
+58
+87
+110
+80
+110
+29
+27
+145
+94
+19
+42
+74
+86
+96
+127
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.16.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.16.txt
new file mode 100644
index 0000000..dcce408
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.16.txt
@@ -0,0 +1,20 @@
+32
+52
+93
+20
+24
+135
+194
+71
+60
+212
+128
+109
+432
+197
+28
+123
+301
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.18.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.18.txt
new file mode 100644
index 0000000..aba09a8
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.18.txt
@@ -0,0 +1,20 @@
+76
+139
+15
+150
+82
+23
+125
+226
+116
+246
+76
+80
+135
+110
+64
+58
+412
+214
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.2.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.2.txt
new file mode 100644
index 0000000..6ca6f3e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.2.txt
@@ -0,0 +1,20 @@
+30
+68
+66
+152
+110
+127
+46
+46
+235
+91
+93
+48
+90
+159
+124
+435
+118
+-1
+356
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.22.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.22.txt
new file mode 100644
index 0000000..8976bfb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.22.txt
@@ -0,0 +1,20 @@
+16
+55
+61
+56
+21
+172
+211
+74
+271
+108
+141
+396
+35
+79
+149
+224
+353
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.24.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.24.txt
new file mode 100644
index 0000000..e88b8bf
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.24.txt
@@ -0,0 +1,20 @@
+16
+39
+30
+42
+17
+46
+74
+83
+63
+43
+54
+56
+96
+84
+103
+85
+52
+110
+194
+336
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.27.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.27.txt
new file mode 100644
index 0000000..4689367
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.27.txt
@@ -0,0 +1,20 @@
+37
+56
+80
+172
+186
+103
+33
+63
+358
+117
+349
+19
+41
+53
+-1
+132
+395
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.29.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.29.txt
new file mode 100644
index 0000000..2146e44
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.29.txt
@@ -0,0 +1,20 @@
+16
+15
+26
+31
+40
+53
+23
+53
+113
+160
+33
+76
+157
+176
+129
+106
+232
+402
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.31.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.31.txt
new file mode 100644
index 0000000..1fcebcc
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.31.txt
@@ -0,0 +1,20 @@
+73
+63
+34
+114
+41
+121
+128
+44
+45
+181
+66
+21
+76
+67
+44
+147
+132
+286
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.33.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.33.txt
new file mode 100644
index 0000000..065ef77
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.33.txt
@@ -0,0 +1,20 @@
+17
+65
+107
+139
+119
+37
+135
+49
+230
+149
+175
+363
+390
+120
+72
+29
+-1
+-1
+501
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.36.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.36.txt
new file mode 100644
index 0000000..e98a491
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.36.txt
@@ -0,0 +1,20 @@
+41
+64
+158
+106
+216
+44
+20
+249
+241
+14
+209
+132
+59
+96
+102
+-1
+-1
+493
+389
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.38.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.38.txt
new file mode 100644
index 0000000..23942fa
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.38.txt
@@ -0,0 +1,20 @@
+22
+58
+99
+99
+76
+109
+20
+178
+34
+16
+102
+107
+83
+91
+69
+381
+445
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.4.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.4.txt
new file mode 100644
index 0000000..9e0dcc8
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob0.4.txt
@@ -0,0 +1,20 @@
+45
+40
+55
+15
+80
+68
+53
+196
+277
+116
+194
+23
+15
+265
+84
+-1
+469
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.0.txt
new file mode 100644
index 0000000..8b47c05
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.0.txt
@@ -0,0 +1,20 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.11.txt
new file mode 100644
index 0000000..439392f
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.11.txt
@@ -0,0 +1,20 @@
+24
+46
+51
+25
+114
+134
+46
+59
+137
+78
+72
+137
+18
+67
+39
+-1
+92
+159
+143
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.22.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.22.txt
new file mode 100644
index 0000000..9103731
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.22.txt
@@ -0,0 +1,20 @@
+29
+45
+97
+99
+233
+85
+103
+333
+110
+429
+77
+-1
+51
+81
+-1
+560
+481
+218
+-1
+207
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.33.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.33.txt
new file mode 100644
index 0000000..0a8d52e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.33.txt
@@ -0,0 +1,20 @@
+38
+31
+52
+52
+83
+27
+41
+34
+164
+75
+14
+119
+66
+97
+168
+77
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.44.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.44.txt
new file mode 100644
index 0000000..75b9942
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.44.txt
@@ -0,0 +1,20 @@
+43
+112
+125
+143
+41
+38
+62
+65
+66
+222
+61
+30
+497
+57
+-1
+225
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.56.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.56.txt
new file mode 100644
index 0000000..c935e2c
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.56.txt
@@ -0,0 +1,20 @@
+108
+189
+250
+268
+367
+146
+240
+93
+97
+542
+23
+-1
+312
+-1
+443
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.67.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.67.txt
new file mode 100644
index 0000000..d68d684
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.67.txt
@@ -0,0 +1,20 @@
+42
+58
+33
+104
+146
+195
+251
+179
+184
+196
+49
+112
+224
+230
+251
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.78.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.78.txt
new file mode 100644
index 0000000..a0b6480
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.78.txt
@@ -0,0 +1,20 @@
+103
+140
+211
+198
+64
+211
+214
+151
+119
+402
+69
+71
+82
+37
+59
+-1
+199
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.89.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.89.txt
new file mode 100644
index 0000000..57cf01e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob0.89.txt
@@ -0,0 +1,20 @@
+27
+32
+27
+60
+75
+136
+137
+162
+177
+169
+69
+85
+428
+-1
+-1
+286
+-1
+-1
+577
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob1.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob1.0.txt
new file mode 100644
index 0000000..6e20caf
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob1.0.txt
@@ -0,0 +1,20 @@
+15
+46
+77
+120
+233
+194
+131
+260
+259
+14
+545
+-1
+93
+-1
+-1
+538
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob_times.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob_times.txt
new file mode 100644
index 0000000..76da838
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k8prob_times.txt
@@ -0,0 +1,10 @@
+1st file: "howManyGenerations_5x5_20_600gen_k8prob0.0.txt"
+
+0.0: 15.64s
+0.11: 158.63s
+0.22: 153.62s
+0.33: 121.46s
+0.44: 144.53s
+0.56: 171.68s
+0.67: 137.82s
+0.78: 101.41s
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_1000_600gen_k8prob0.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_1000_600gen_k8prob0.0.txt
new file mode 100644
index 0000000..033cb5b
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_1000_600gen_k8prob0.0.txt
@@ -0,0 +1,1000 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.0.txt
new file mode 100644
index 0000000..8cd991e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.0.txt
@@ -0,0 +1,300 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.05.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.05.txt
new file mode 100644
index 0000000..9be3151
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.05.txt
@@ -0,0 +1,300 @@
+-1
+-1
+-1
+48
+-1
+-1
+-1
+-1
+59
+-1
+-1
+-1
+-1
+24
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+39
+-1
+30
+-1
+-1
+-1
+31
+-1
+28
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+28
+-1
+52
+-1
+-1
+-1
+249
+-1
+-1
+55
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+61
+-1
+113
+-1
+36
+-1
+-1
+-1
+-1
+33
+-1
+-1
+32
+20
+156
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+45
+-1
+-1
+-1
+-1
+21
+-1
+-1
+-1
+-1
+74
+26
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+41
+-1
+-1
+-1
+51
+-1
+-1
+-1
+-1
+29
+-1
+58
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+20
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+26
+-1
+-1
+-1
+34
+-1
+-1
+30
+-1
+-1
+33
+-1
+-1
+33
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+17
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+48
+85
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+27
+-1
+-1
+42
+24
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+31
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+43
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+50
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.11.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.11.txt
new file mode 100644
index 0000000..d3fa1f9
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.11.txt
@@ -0,0 +1,300 @@
+28
+35
+19
+32
+80
+-1
+42
+14
+148
+110
+47
+48
+-1
+67
+-1
+26
+75
+15
+393
+40
+70
+138
+469
+-1
+55
+-1
+322
+115
+229
+56
+108
+130
+25
+320
+81
+-1
+113
+81
+222
+84
+-1
+61
+-1
+135
+93
+119
+86
+202
+215
+31
+20
+114
+195
+115
+151
+47
+29
+-1
+242
+524
+18
+22
+24
+46
+106
+66
+-1
+-1
+-1
+66
+85
+82
+43
+36
+51
+121
+-1
+94
+41
+322
+-1
+71
+32
+21
+15
+47
+72
+-1
+58
+64
+218
+24
+28
+31
+43
+-1
+80
+203
+18
+48
+50
+15
+-1
+36
+22
+71
+69
+50
+-1
+271
+94
+90
+122
+71
+34
+40
+-1
+71
+598
+59
+42
+-1
+172
+357
+154
+-1
+-1
+-1
+258
+46
+47
+25
+45
+67
+96
+40
+118
+43
+16
+77
+39
+99
+31
+76
+-1
+101
+302
+216
+44
+75
+45
+96
+58
+295
+58
+17
+24
+128
+55
+-1
+56
+85
+213
+95
+82
+38
+66
+-1
+120
+93
+-1
+80
+215
+87
+-1
+-1
+81
+-1
+101
+376
+-1
+-1
+39
+74
+58
+-1
+-1
+69
+37
+64
+51
+59
+-1
+109
+129
+49
+135
+129
+72
+150
+-1
+45
+-1
+34
+123
+417
+-1
+75
+-1
+31
+-1
+-1
+100
+277
+123
+259
+95
+124
+92
+18
+-1
+58
+60
+40
+82
+-1
+42
+95
+55
+17
+74
+-1
+68
+185
+46
+110
+26
+-1
+-1
+78
+-1
+165
+129
+92
+205
+52
+29
+67
+88
+-1
+169
+62
+-1
+-1
+94
+191
+319
+196
+-1
+66
+57
+-1
+93
+-1
+49
+-1
+73
+18
+24
+179
+46
+91
+-1
+157
+33
+-1
+15
+40
+49
+261
+68
+-1
+-1
+42
+33
+-1
+36
+129
+102
+56
+296
+24
+22
+50
+34
+14
+44
+35
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.16.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.16.txt
new file mode 100644
index 0000000..8c5bf51
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.16.txt
@@ -0,0 +1,300 @@
+244
+47
+407
+31
+111
+47
+-1
+43
+-1
+-1
+-1
+113
+111
+66
+84
+215
+141
+-1
+129
+107
+57
+50
+194
+271
+185
+68
+77
+227
+65
+73
+80
+-1
+82
+123
+47
+72
+37
+131
+87
+-1
+493
+429
+-1
+-1
+560
+-1
+134
+75
+170
+41
+99
+21
+112
+18
+33
+149
+41
+52
+143
+18
+100
+-1
+292
+49
+341
+36
+87
+-1
+109
+-1
+247
+46
+17
+41
+68
+53
+322
+18
+160
+191
+34
+131
+138
+87
+24
+17
+314
+71
+231
+26
+42
+19
+104
+-1
+31
+142
+72
+109
+84
+35
+47
+286
+-1
+253
+143
+269
+368
+55
+20
+82
+20
+24
+-1
+111
+-1
+152
+214
+60
+89
+22
+194
+157
+78
+577
+121
+14
+231
+26
+-1
+-1
+55
+90
+73
+67
+99
+67
+43
+198
+67
+21
+233
+29
+18
+82
+35
+61
+56
+117
+40
+15
+27
+84
+68
+-1
+105
+55
+53
+175
+-1
+194
+131
+35
+102
+159
+-1
+309
+61
+195
+74
+35
+14
+39
+397
+100
+539
+170
+252
+81
+184
+91
+223
+-1
+22
+43
+122
+-1
+20
+51
+102
+62
+129
+503
+219
+141
+-1
+272
+56
+-1
+91
+16
+81
+232
+444
+173
+116
+245
+-1
+-1
+64
+307
+59
+39
+28
+-1
+152
+234
+94
+142
+66
+22
+174
+317
+-1
+45
+477
+80
+-1
+138
+447
+-1
+530
+-1
+18
+-1
+-1
+183
+-1
+170
+69
+60
+61
+31
+148
+135
+56
+98
+-1
+38
+19
+122
+60
+215
+96
+57
+-1
+179
+107
+158
+45
+109
+157
+189
+37
+36
+207
+71
+143
+48
+77
+35
+67
+254
+-1
+14
+402
+141
+450
+149
+-1
+66
+40
+273
+68
+270
+160
+123
+97
+15
+48
+56
+183
+274
+177
+251
+-1
+58
+122
+96
+156
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.21.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.21.txt
new file mode 100644
index 0000000..9a9f163
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.21.txt
@@ -0,0 +1,300 @@
+27
+63
+31
+93
+130
+147
+328
+32
+208
+-1
+-1
+46
+107
+286
+51
+69
+157
+186
+40
+153
+153
+96
+31
+14
+66
+45
+-1
+-1
+571
+20
+301
+-1
+413
+-1
+132
+116
+141
+16
+16
+42
+62
+58
+35
+34
+79
+21
+-1
+-1
+143
+94
+-1
+175
+23
+37
+-1
+-1
+156
+-1
+174
+236
+137
+54
+24
+14
+-1
+-1
+88
+203
+64
+113
+97
+60
+281
+-1
+83
+69
+-1
+-1
+-1
+-1
+50
+118
+87
+513
+29
+-1
+212
+170
+90
+412
+35
+86
+21
+-1
+-1
+58
+60
+15
+94
+32
+166
+381
+90
+-1
+22
+135
+354
+192
+-1
+29
+131
+68
+70
+-1
+39
+566
+-1
+-1
+14
+178
+191
+-1
+134
+17
+34
+-1
+-1
+47
+220
+81
+60
+96
+104
+-1
+92
+163
+-1
+49
+21
+343
+-1
+63
+460
+18
+112
+92
+198
+44
+280
+58
+231
+83
+102
+26
+23
+93
+68
+40
+-1
+33
+-1
+-1
+136
+108
+17
+56
+43
+16
+238
+41
+101
+117
+-1
+-1
+-1
+33
+59
+23
+44
+98
+90
+93
+14
+59
+-1
+23
+136
+47
+41
+261
+56
+123
+71
+135
+17
+54
+41
+-1
+61
+101
+278
+162
+195
+223
+33
+28
+58
+89
+114
+44
+93
+145
+168
+35
+46
+246
+37
+55
+-1
+40
+32
+259
+135
+87
+150
+46
+85
+96
+-1
+-1
+116
+183
+17
+209
+428
+-1
+16
+-1
+237
+83
+83
+176
+95
+233
+115
+153
+189
+122
+166
+21
+31
+296
+-1
+28
+49
+233
+56
+104
+32
+29
+33
+16
+273
+318
+122
+204
+97
+65
+33
+140
+-1
+168
+20
+168
+58
+50
+14
+94
+156
+24
+396
+158
+568
+-1
+-1
+32
+90
+56
+16
+-1
+67
+64
+66
+-1
+-1
+72
+-1
+89
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.26.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.26.txt
new file mode 100644
index 0000000..4f1d00d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.26.txt
@@ -0,0 +1,300 @@
+18
+104
+163
+64
+85
+-1
+-1
+195
+21
+284
+21
+-1
+363
+70
+104
+-1
+358
+50
+-1
+179
+47
+72
+113
+42
+163
+153
+-1
+111
+129
+38
+-1
+180
+-1
+51
+46
+84
+32
+111
+508
+244
+59
+35
+45
+195
+229
+70
+217
+-1
+40
+170
+64
+254
+370
+142
+-1
+33
+312
+64
+98
+44
+52
+134
+42
+485
+42
+171
+103
+115
+125
+74
+301
+50
+-1
+168
+31
+49
+199
+-1
+41
+73
+95
+41
+136
+106
+-1
+175
+245
+23
+17
+145
+-1
+-1
+120
+122
+47
+235
+-1
+-1
+71
+61
+252
+104
+78
+-1
+312
+163
+-1
+22
+90
+17
+192
+187
+27
+574
+85
+-1
+356
+101
+231
+208
+424
+346
+166
+46
+120
+44
+454
+15
+278
+301
+43
+519
+201
+112
+83
+16
+85
+14
+95
+138
+22
+-1
+117
+22
+115
+91
+138
+174
+39
+42
+-1
+242
+-1
+39
+64
+-1
+73
+-1
+-1
+400
+-1
+45
+131
+68
+209
+40
+188
+449
+106
+36
+62
+89
+-1
+62
+49
+-1
+47
+138
+55
+73
+-1
+37
+301
+113
+75
+-1
+102
+-1
+199
+114
+103
+26
+15
+92
+75
+214
+107
+47
+167
+32
+65
+129
+87
+217
+26
+-1
+194
+65
+38
+-1
+40
+107
+201
+92
+130
+21
+50
+-1
+335
+218
+31
+219
+-1
+69
+-1
+33
+-1
+54
+58
+159
+-1
+47
+92
+42
+-1
+56
+-1
+391
+-1
+40
+14
+15
+63
+231
+228
+-1
+164
+-1
+86
+62
+218
+-1
+-1
+61
+51
+16
+252
+48
+491
+-1
+76
+73
+113
+530
+135
+218
+233
+315
+-1
+-1
+377
+23
+29
+26
+-1
+160
+-1
+15
+72
+18
+-1
+21
+559
+63
+34
+68
+-1
+-1
+32
+163
+100
+164
+67
+39
+77
+196
+304
+147
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.32.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.32.txt
new file mode 100644
index 0000000..3cb523d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.32.txt
@@ -0,0 +1,300 @@
+113
+60
+345
+-1
+-1
+73
+87
+133
+46
+108
+50
+-1
+53
+67
+22
+37
+76
+15
+102
+44
+157
+63
+546
+-1
+44
+16
+16
+21
+192
+165
+-1
+80
+220
+-1
+166
+63
+65
+71
+193
+145
+115
+53
+304
+338
+214
+204
+203
+265
+175
+184
+-1
+183
+-1
+398
+85
+-1
+209
+390
+-1
+270
+-1
+73
+35
+-1
+-1
+26
+-1
+68
+151
+115
+57
+395
+-1
+246
+87
+491
+138
+-1
+357
+104
+182
+248
+15
+335
+41
+22
+-1
+232
+303
+30
+24
+202
+201
+20
+67
+69
+42
+105
+90
+60
+76
+68
+63
+253
+-1
+45
+53
+24
+193
+73
+351
+159
+52
+15
+69
+94
+-1
+467
+37
+30
+218
+213
+28
+-1
+23
+393
+71
+141
+431
+37
+223
+56
+115
+300
+-1
+30
+21
+-1
+41
+52
+233
+168
+25
+246
+80
+54
+-1
+-1
+32
+228
+25
+36
+120
+178
+517
+26
+-1
+15
+101
+176
+-1
+25
+50
+164
+-1
+74
+57
+59
+-1
+61
+256
+16
+122
+404
+142
+-1
+35
+-1
+99
+186
+-1
+54
+58
+117
+-1
+59
+322
+190
+-1
+121
+233
+90
+178
+56
+139
+-1
+19
+221
+111
+-1
+434
+34
+200
+198
+249
+68
+-1
+52
+-1
+183
+111
+-1
+86
+170
+113
+24
+265
+174
+120
+293
+202
+129
+186
+-1
+16
+51
+-1
+246
+219
+528
+356
+531
+69
+505
+109
+59
+31
+67
+32
+410
+25
+20
+-1
+48
+217
+41
+102
+16
+37
+318
+159
+94
+179
+52
+74
+-1
+483
+14
+253
+-1
+150
+69
+35
+48
+-1
+-1
+28
+52
+292
+64
+386
+71
+72
+159
+123
+291
+77
+-1
+290
+72
+65
+37
+16
+36
+22
+40
+-1
+229
+272
+67
+318
+194
+529
+24
+178
+170
+98
+53
+71
+154
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.37.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.37.txt
new file mode 100644
index 0000000..1c55408
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.37.txt
@@ -0,0 +1,300 @@
+155
+199
+16
+312
+103
+275
+45
+126
+260
+-1
+82
+19
+102
+196
+45
+247
+59
+105
+20
+-1
+88
+14
+196
+21
+-1
+19
+-1
+69
+-1
+43
+138
+68
+80
+426
+-1
+-1
+-1
+379
+80
+67
+25
+62
+35
+-1
+112
+33
+225
+369
+-1
+123
+93
+224
+144
+-1
+179
+143
+467
+159
+365
+120
+169
+155
+-1
+137
+16
+-1
+28
+161
+-1
+59
+34
+355
+71
+64
+277
+34
+-1
+-1
+50
+73
+74
+42
+55
+45
+179
+30
+15
+-1
+344
+89
+200
+-1
+-1
+287
+-1
+39
+77
+360
+71
+20
+15
+17
+-1
+-1
+223
+52
+180
+14
+190
+-1
+-1
+229
+-1
+259
+48
+88
+18
+381
+87
+25
+83
+167
+-1
+-1
+256
+194
+-1
+102
+-1
+111
+109
+60
+127
+42
+-1
+199
+25
+16
+66
+-1
+148
+529
+33
+78
+363
+45
+40
+129
+92
+-1
+67
+39
+38
+99
+27
+275
+-1
+-1
+222
+196
+190
+527
+-1
+51
+63
+-1
+110
+374
+283
+207
+114
+206
+162
+150
+-1
+-1
+211
+-1
+273
+334
+-1
+33
+240
+95
+95
+45
+66
+55
+336
+-1
+108
+419
+173
+-1
+87
+246
+197
+132
+52
+217
+-1
+43
+233
+158
+203
+-1
+129
+49
+341
+45
+150
+75
+188
+14
+50
+-1
+233
+110
+-1
+29
+55
+183
+217
+401
+77
+37
+70
+279
+79
+111
+14
+61
+51
+-1
+108
+57
+56
+-1
+192
+574
+111
+53
+25
+39
+-1
+-1
+190
+187
+43
+230
+-1
+152
+133
+202
+53
+-1
+168
+32
+152
+135
+34
+39
+214
+-1
+292
+153
+15
+59
+15
+223
+-1
+505
+32
+20
+17
+58
+51
+70
+496
+291
+323
+122
+67
+188
+481
+-1
+60
+203
+173
+282
+20
+21
+199
+-1
+-1
+103
+82
+-1
+109
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.42.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.42.txt
new file mode 100644
index 0000000..69fd650
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.42.txt
@@ -0,0 +1,300 @@
+14
+64
+93
+20
+188
+252
+293
+403
+43
+47
+26
+386
+74
+129
+54
+130
+194
+78
+-1
+141
+221
+97
+494
+15
+170
+47
+29
+35
+73
+-1
+84
+188
+45
+186
+16
+99
+-1
+182
+130
+62
+-1
+172
+-1
+22
+-1
+109
+139
+94
+295
+68
+161
+36
+98
+-1
+123
+42
+32
+38
+-1
+72
+69
+229
+-1
+356
+-1
+-1
+243
+44
+30
+-1
+-1
+343
+103
+-1
+54
+101
+-1
+118
+77
+-1
+193
+56
+-1
+164
+-1
+349
+-1
+173
+174
+29
+588
+218
+264
+36
+264
+144
+322
+17
+-1
+15
+108
+44
+84
+541
+173
+108
+-1
+141
+499
+205
+37
+292
+230
+150
+432
+227
+-1
+53
+16
+-1
+215
+14
+53
+315
+-1
+93
+437
+55
+167
+177
+41
+182
+286
+16
+260
+148
+67
+29
+67
+182
+44
+92
+-1
+92
+212
+-1
+339
+67
+-1
+55
+42
+89
+66
+-1
+66
+282
+-1
+208
+56
+33
+28
+-1
+35
+-1
+196
+498
+62
+61
+69
+23
+44
+43
+-1
+406
+130
+81
+-1
+61
+314
+41
+186
+231
+-1
+104
+-1
+26
+139
+45
+42
+193
+27
+122
+552
+-1
+111
+333
+318
+37
+288
+-1
+57
+22
+45
+185
+377
+44
+153
+76
+134
+48
+30
+135
+67
+117
+47
+42
+167
+216
+147
+-1
+35
+-1
+110
+37
+207
+38
+89
+38
+-1
+140
+200
+-1
+39
+17
+20
+15
+138
+26
+435
+-1
+77
+70
+69
+43
+67
+193
+49
+123
+208
+72
+106
+199
+-1
+65
+156
+39
+156
+50
+93
+44
+-1
+298
+214
+360
+-1
+217
+90
+99
+315
+-1
+343
+545
+-1
+151
+31
+-1
+71
+253
+-1
+31
+50
+89
+95
+56
+76
+129
+104
+454
+70
+-1
+21
+124
+-1
+31
+200
+334
+333
+-1
+296
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.47.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.47.txt
new file mode 100644
index 0000000..72e569f
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.47.txt
@@ -0,0 +1,300 @@
+108
+245
+260
+243
+86
+232
+51
+96
+263
+101
+-1
+163
+18
+248
+57
+53
+44
+380
+216
+153
+311
+210
+60
+-1
+77
+101
+537
+197
+-1
+56
+85
+154
+132
+-1
+437
+127
+263
+-1
+183
+131
+66
+117
+91
+87
+244
+186
+324
+97
+-1
+39
+-1
+-1
+-1
+129
+413
+108
+373
+89
+181
+68
+-1
+51
+173
+208
+44
+140
+95
+222
+45
+-1
+-1
+157
+45
+-1
+16
+-1
+44
+132
+26
+95
+87
+147
+179
+129
+23
+-1
+65
+78
+384
+-1
+123
+28
+-1
+190
+357
+52
+-1
+-1
+30
+149
+-1
+196
+-1
+197
+241
+-1
+107
+71
+170
+477
+-1
+82
+42
+149
+80
+407
+-1
+-1
+434
+76
+208
+156
+66
+297
+29
+-1
+230
+342
+139
+113
+379
+448
+191
+364
+34
+553
+60
+45
+60
+123
+-1
+14
+190
+-1
+-1
+-1
+308
+177
+222
+95
+116
+350
+-1
+-1
+-1
+-1
+-1
+98
+89
+-1
+59
+197
+53
+116
+41
+-1
+117
+-1
+15
+46
+-1
+-1
+149
+-1
+-1
+-1
+136
+143
+138
+-1
+-1
+61
+80
+-1
+66
+80
+89
+52
+48
+37
+442
+83
+184
+123
+145
+27
+204
+521
+338
+395
+63
+91
+210
+168
+29
+209
+-1
+197
+71
+-1
+-1
+151
+155
+-1
+459
+52
+68
+347
+-1
+-1
+38
+22
+155
+206
+-1
+46
+103
+16
+-1
+83
+163
+117
+74
+-1
+-1
+374
+360
+245
+18
+-1
+122
+315
+53
+80
+564
+-1
+62
+324
+-1
+-1
+-1
+98
+-1
+178
+161
+15
+79
+156
+228
+27
+127
+-1
+118
+381
+296
+98
+22
+14
+-1
+21
+167
+195
+19
+214
+61
+568
+-1
+359
+38
+91
+27
+-1
+576
+58
+15
+490
+100
+67
+390
+213
+35
+-1
+53
+-1
+179
+111
+211
+208
+519
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.53.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.53.txt
new file mode 100644
index 0000000..b3d37c0
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.53.txt
@@ -0,0 +1,300 @@
+31
+43
+207
+104
+57
+437
+27
+99
+142
+-1
+63
+56
+114
+216
+92
+130
+43
+178
+-1
+25
+194
+187
+113
+-1
+48
+109
+155
+-1
+130
+314
+-1
+498
+-1
+190
+16
+128
+-1
+68
+311
+-1
+195
+69
+379
+17
+72
+37
+-1
+95
+312
+323
+154
+77
+64
+101
+101
+268
+137
+122
+192
+95
+146
+441
+76
+49
+-1
+25
+72
+506
+-1
+94
+53
+195
+107
+272
+-1
+162
+19
+68
+49
+80
+41
+189
+370
+49
+127
+84
+47
+41
+-1
+155
+227
+578
+-1
+51
+91
+48
+-1
+107
+279
+374
+504
+38
+201
+306
+42
+-1
+163
+58
+231
+-1
+-1
+-1
+185
+22
+58
+-1
+214
+20
+132
+40
+-1
+-1
+599
+93
+14
+203
+-1
+98
+-1
+-1
+22
+560
+187
+204
+78
+242
+-1
+37
+156
+-1
+45
+198
+43
+201
+-1
+221
+-1
+178
+20
+-1
+20
+48
+44
+50
+34
+77
+17
+-1
+99
+-1
+56
+179
+57
+83
+522
+-1
+416
+281
+49
+193
+101
+48
+14
+62
+64
+86
+192
+64
+71
+77
+84
+67
+274
+595
+136
+167
+451
+107
+139
+-1
+61
+122
+127
+-1
+49
+120
+-1
+91
+47
+-1
+-1
+322
+248
+232
+84
+125
+149
+393
+70
+121
+-1
+-1
+-1
+-1
+326
+21
+64
+321
+-1
+25
+51
+-1
+55
+72
+99
+-1
+196
+-1
+222
+55
+475
+220
+403
+37
+-1
+66
+-1
+44
+-1
+205
+111
+185
+205
+78
+38
+195
+-1
+423
+170
+-1
+424
+18
+110
+17
+30
+106
+248
+112
+51
+126
+259
+330
+178
+77
+113
+157
+79
+192
+193
+134
+118
+-1
+119
+-1
+-1
+439
+-1
+146
+115
+292
+491
+117
+151
+-1
+98
+51
+80
+310
+-1
+37
+73
+38
+162
+-1
+-1
+89
+14
+163
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.58.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.58.txt
new file mode 100644
index 0000000..b7602d2
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.58.txt
@@ -0,0 +1,300 @@
+104
+98
+27
+16
+135
+182
+-1
+171
+18
+-1
+204
+151
+192
+35
+-1
+43
+-1
+-1
+200
+106
+130
+157
+185
+89
+164
+-1
+95
+224
+16
+348
+117
+57
+192
+153
+227
+243
+25
+42
+77
+38
+22
+73
+266
+152
+137
+81
+34
+-1
+25
+124
+535
+-1
+95
+179
+64
+124
+122
+223
+-1
+-1
+162
+62
+18
+119
+-1
+76
+-1
+246
+63
+-1
+206
+152
+80
+61
+180
+48
+371
+94
+-1
+-1
+182
+341
+410
+239
+67
+115
+83
+85
+223
+269
+265
+75
+-1
+127
+-1
+-1
+82
+300
+51
+187
+135
+444
+49
+166
+60
+34
+-1
+61
+-1
+291
+73
+-1
+-1
+383
+-1
+-1
+20
+-1
+181
+154
+59
+62
+-1
+134
+231
+137
+174
+-1
+223
+446
+61
+14
+32
+77
+53
+129
+213
+113
+142
+284
+136
+55
+-1
+-1
+110
+120
+85
+137
+-1
+99
+139
+-1
+355
+40
+94
+-1
+121
+143
+32
+103
+23
+363
+-1
+352
+-1
+-1
+158
+39
+-1
+43
+43
+47
+163
+84
+86
+26
+196
+-1
+102
+106
+227
+50
+135
+59
+153
+305
+-1
+151
+-1
+46
+66
+239
+-1
+15
+16
+190
+176
+207
+31
+-1
+358
+28
+75
+60
+16
+84
+258
+91
+43
+-1
+118
+67
+54
+489
+375
+191
+192
+231
+431
+51
+-1
+-1
+220
+55
+-1
+67
+40
+59
+276
+135
+-1
+210
+208
+62
+276
+310
+51
+14
+-1
+82
+140
+81
+83
+109
+64
+90
+306
+-1
+208
+35
+27
+-1
+41
+40
+50
+196
+-1
+169
+153
+15
+-1
+149
+63
+-1
+91
+502
+71
+18
+76
+155
+-1
+86
+120
+95
+65
+56
+222
+-1
+71
+433
+53
+120
+179
+29
+357
+127
+62
+583
+-1
+-1
+223
+65
+426
+48
+203
+80
+96
+106
+-1
+390
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.63.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.63.txt
new file mode 100644
index 0000000..74795a4
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.63.txt
@@ -0,0 +1,300 @@
+150
+141
+428
+107
+110
+-1
+-1
+53
+94
+55
+144
+284
+104
+68
+268
+201
+260
+68
+-1
+-1
+34
+160
+137
+112
+220
+132
+195
+75
+88
+260
+24
+56
+29
+-1
+49
+519
+66
+-1
+123
+61
+230
+92
+424
+95
+189
+298
+-1
+212
+83
+290
+76
+188
+351
+142
+163
+101
+208
+88
+17
+-1
+34
+225
+-1
+101
+76
+201
+121
+36
+-1
+79
+60
+187
+34
+36
+279
+61
+59
+142
+162
+263
+-1
+177
+-1
+-1
+31
+160
+207
+513
+16
+93
+16
+68
+82
+41
+150
+-1
+-1
+310
+176
+147
+-1
+227
+197
+200
+14
+193
+22
+-1
+133
+145
+92
+-1
+-1
+89
+183
+60
+19
+-1
+-1
+-1
+184
+-1
+-1
+80
+99
+292
+144
+41
+157
+103
+-1
+23
+-1
+-1
+119
+74
+58
+61
+-1
+75
+189
+-1
+207
+-1
+88
+75
+-1
+110
+95
+209
+483
+-1
+283
+47
+138
+-1
+235
+16
+222
+71
+54
+226
+-1
+443
+49
+167
+100
+-1
+166
+211
+430
+83
+241
+-1
+131
+271
+279
+480
+183
+-1
+-1
+-1
+211
+31
+178
+228
+60
+149
+310
+168
+232
+-1
+156
+190
+-1
+271
+-1
+-1
+220
+-1
+343
+233
+218
+81
+-1
+-1
+189
+-1
+-1
+-1
+113
+113
+19
+44
+47
+-1
+73
+194
+-1
+33
+75
+409
+31
+39
+139
+99
+56
+198
+72
+392
+120
+-1
+205
+51
+138
+-1
+213
+220
+96
+24
+63
+61
+-1
+-1
+149
+103
+72
+143
+204
+187
+378
+20
+63
+-1
+81
+117
+127
+327
+323
+43
+105
+-1
+45
+380
+79
+130
+45
+191
+284
+122
+-1
+64
+43
+54
+50
+149
+257
+187
+-1
+317
+340
+357
+135
+-1
+142
+74
+143
+27
+80
+-1
+37
+273
+54
+148
+111
+58
+102
+131
+490
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.68.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.68.txt
new file mode 100644
index 0000000..5394445
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.68.txt
@@ -0,0 +1,300 @@
+113
+94
+114
+470
+205
+73
+39
+165
+-1
+592
+-1
+-1
+14
+300
+460
+-1
+-1
+78
+69
+101
+-1
+48
+89
+-1
+152
+93
+198
+298
+214
+-1
+-1
+116
+31
+181
+129
+50
+186
+55
+229
+-1
+38
+121
+-1
+128
+34
+444
+33
+267
+23
+59
+175
+42
+225
+-1
+91
+138
+137
+22
+28
+188
+37
+145
+93
+-1
+16
+150
+451
+162
+96
+165
+-1
+198
+57
+275
+31
+143
+241
+200
+106
+80
+106
+192
+45
+336
+58
+-1
+87
+43
+45
+332
+202
+66
+118
+247
+47
+23
+94
+95
+85
+56
+170
+113
+103
+41
+77
+242
+-1
+401
+238
+131
+244
+35
+53
+-1
+79
+29
+-1
+48
+56
+49
+-1
+89
+-1
+279
+44
+-1
+-1
+21
+16
+70
+33
+17
+-1
+162
+-1
+46
+-1
+-1
+81
+202
+222
+-1
+348
+69
+75
+28
+-1
+176
+431
+-1
+-1
+439
+87
+142
+-1
+52
+194
+149
+17
+89
+105
+42
+213
+108
+110
+34
+68
+55
+-1
+68
+75
+422
+204
+-1
+90
+-1
+143
+548
+89
+73
+124
+41
+128
+-1
+56
+130
+96
+108
+460
+34
+193
+-1
+-1
+100
+-1
+24
+266
+303
+-1
+-1
+-1
+-1
+116
+74
+381
+-1
+65
+94
+-1
+150
+111
+112
+106
+76
+154
+-1
+-1
+152
+83
+56
+37
+198
+-1
+48
+390
+60
+196
+484
+323
+-1
+14
+77
+69
+94
+-1
+-1
+45
+159
+47
+124
+-1
+83
+-1
+64
+64
+37
+30
+-1
+45
+-1
+-1
+56
+-1
+57
+193
+514
+168
+38
+224
+106
+-1
+251
+14
+90
+261
+-1
+-1
+274
+-1
+593
+183
+-1
+219
+19
+137
+56
+-1
+157
+121
+39
+-1
+196
+223
+367
+62
+129
+-1
+-1
+-1
+40
+138
+-1
+392
+113
+65
+161
+462
+217
+453
+162
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.74.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.74.txt
new file mode 100644
index 0000000..05a1864
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.74.txt
@@ -0,0 +1,300 @@
+135
+31
+190
+50
+38
+-1
+433
+122
+61
+162
+-1
+112
+265
+15
+-1
+44
+-1
+-1
+417
+-1
+44
+368
+76
+93
+435
+479
+172
+141
+386
+39
+-1
+-1
+-1
+-1
+123
+122
+63
+211
+-1
+-1
+-1
+-1
+165
+193
+-1
+84
+124
+74
+217
+-1
+37
+170
+216
+195
+-1
+75
+26
+165
+159
+-1
+-1
+389
+75
+93
+299
+118
+-1
+-1
+147
+139
+-1
+54
+-1
+-1
+251
+185
+-1
+230
+128
+311
+241
+110
+293
+175
+73
+38
+152
+46
+277
+90
+45
+114
+-1
+67
+75
+107
+-1
+39
+120
+63
+-1
+14
+-1
+173
+-1
+403
+228
+-1
+366
+37
+70
+92
+33
+86
+26
+365
+-1
+251
+272
+27
+32
+75
+70
+25
+347
+-1
+381
+-1
+98
+15
+90
+81
+203
+175
+277
+-1
+209
+69
+181
+294
+-1
+74
+178
+146
+171
+106
+348
+43
+41
+75
+-1
+45
+-1
+82
+89
+116
+53
+17
+139
+62
+372
+-1
+165
+297
+29
+70
+394
+56
+-1
+203
+62
+126
+-1
+111
+176
+-1
+63
+-1
+169
+-1
+50
+176
+14
+476
+148
+37
+257
+144
+97
+257
+-1
+-1
+218
+-1
+-1
+191
+149
+246
+16
+-1
+91
+-1
+20
+124
+44
+-1
+-1
+82
+116
+-1
+-1
+85
+22
+27
+177
+15
+-1
+161
+269
+177
+-1
+-1
+279
+129
+272
+-1
+36
+277
+135
+420
+166
+118
+225
+84
+133
+-1
+242
+368
+269
+69
+33
+-1
+362
+529
+340
+41
+73
+70
+-1
+52
+70
+66
+171
+229
+170
+53
+479
+56
+541
+200
+-1
+-1
+268
+124
+231
+-1
+188
+-1
+193
+45
+371
+69
+34
+-1
+-1
+-1
+115
+183
+114
+120
+72
+323
+41
+116
+68
+177
+101
+-1
+374
+111
+42
+256
+244
+58
+126
+216
+90
+-1
+230
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.79.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.79.txt
new file mode 100644
index 0000000..4f17c05
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.79.txt
@@ -0,0 +1,300 @@
+113
+187
+188
+314
+164
+129
+351
+61
+-1
+47
+79
+196
+180
+-1
+580
+265
+35
+-1
+187
+-1
+199
+153
+-1
+338
+76
+64
+130
+43
+-1
+46
+279
+102
+135
+-1
+95
+375
+125
+41
+55
+351
+91
+200
+-1
+183
+63
+136
+49
+368
+-1
+277
+153
+137
+94
+145
+55
+288
+49
+73
+-1
+47
+29
+-1
+-1
+150
+199
+178
+121
+121
+-1
+-1
+220
+-1
+-1
+115
+269
+43
+82
+-1
+141
+140
+-1
+142
+84
+249
+228
+189
+-1
+-1
+495
+255
+-1
+62
+129
+-1
+584
+155
+176
+203
+203
+84
+271
+-1
+88
+239
+114
+382
+278
+197
+-1
+-1
+115
+-1
+24
+115
+-1
+401
+202
+-1
+-1
+239
+23
+304
+-1
+85
+48
+56
+326
+63
+520
+55
+63
+67
+24
+44
+120
+85
+-1
+59
+74
+67
+227
+104
+85
+260
+194
+54
+121
+243
+214
+35
+203
+67
+-1
+66
+125
+250
+86
+586
+-1
+-1
+-1
+356
+-1
+382
+354
+155
+131
+14
+159
+35
+85
+187
+-1
+-1
+123
+526
+-1
+-1
+55
+218
+70
+208
+122
+531
+346
+310
+-1
+188
+226
+120
+-1
+-1
+71
+151
+115
+-1
+-1
+336
+588
+128
+65
+101
+-1
+54
+-1
+455
+135
+148
+266
+95
+330
+-1
+60
+56
+103
+-1
+65
+278
+-1
+31
+34
+-1
+86
+250
+-1
+179
+-1
+-1
+-1
+72
+-1
+-1
+46
+254
+-1
+324
+91
+25
+67
+115
+451
+51
+22
+79
+19
+-1
+225
+25
+32
+16
+25
+-1
+58
+198
+-1
+162
+197
+161
+18
+266
+269
+250
+22
+64
+366
+118
+-1
+59
+154
+-1
+337
+407
+129
+53
+76
+-1
+211
+-1
+138
+150
+63
+413
+277
+58
+-1
+15
+38
+15
+110
+242
+118
+-1
+28
+190
+229
+272
+-1
+26
+115
+439
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.84.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.84.txt
new file mode 100644
index 0000000..2cdf51d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.84.txt
@@ -0,0 +1,300 @@
+87
+99
+178
+241
+397
+49
+-1
+339
+58
+206
+126
+35
+102
+278
+124
+43
+94
+182
+14
+201
+-1
+69
+246
+298
+98
+72
+554
+78
+-1
+338
+108
+-1
+269
+253
+80
+186
+350
+49
+181
+-1
+49
+101
+360
+-1
+124
+-1
+202
+57
+-1
+254
+400
+248
+-1
+137
+-1
+14
+61
+168
+-1
+187
+-1
+-1
+78
+-1
+63
+66
+-1
+145
+93
+21
+396
+51
+192
+146
+154
+349
+45
+15
+-1
+63
+123
+325
+78
+-1
+162
+35
+36
+365
+59
+460
+60
+122
+49
+45
+392
+284
+482
+-1
+106
+-1
+-1
+193
+33
+-1
+57
+285
+48
+78
+498
+287
+-1
+165
+14
+46
+-1
+133
+69
+218
+62
+310
+51
+-1
+234
+75
+-1
+116
+114
+-1
+-1
+113
+-1
+101
+-1
+92
+97
+139
+-1
+37
+14
+50
+156
+127
+66
+95
+61
+169
+24
+42
+36
+120
+-1
+586
+223
+-1
+14
+56
+233
+49
+552
+73
+183
+-1
+77
+25
+202
+-1
+64
+-1
+175
+314
+-1
+50
+-1
+-1
+250
+15
+-1
+96
+37
+128
+158
+493
+75
+75
+442
+40
+-1
+235
+445
+358
+137
+79
+478
+115
+592
+80
+64
+41
+118
+131
+34
+-1
+-1
+257
+84
+84
+16
+146
+52
+447
+179
+71
+137
+-1
+71
+38
+76
+132
+155
+-1
+43
+190
+196
+139
+54
+51
+53
+67
+449
+-1
+-1
+21
+175
+269
+116
+194
+156
+442
+100
+-1
+173
+28
+53
+195
+79
+88
+-1
+50
+116
+515
+127
+218
+530
+99
+-1
+-1
+72
+-1
+-1
+583
+441
+-1
+-1
+-1
+58
+77
+48
+-1
+186
+53
+-1
+57
+305
+102
+65
+146
+517
+-1
+20
+-1
+295
+-1
+296
+18
+171
+473
+26
+73
+383
+-1
+231
+169
+68
+258
+15
+55
+184
+57
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.89.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.89.txt
new file mode 100644
index 0000000..1cda42d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.89.txt
@@ -0,0 +1,300 @@
+150
+-1
+-1
+-1
+123
+355
+147
+67
+363
+319
+-1
+259
+15
+-1
+63
+55
+213
+70
+81
+53
+45
+25
+177
+103
+478
+281
+291
+326
+-1
+423
+464
+439
+49
+157
+19
+-1
+51
+418
+56
+31
+266
+217
+200
+-1
+48
+553
+127
+14
+23
+214
+40
+52
+34
+202
+-1
+136
+85
+90
+211
+102
+-1
+-1
+406
+143
+386
+131
+-1
+328
+311
+69
+34
+234
+-1
+146
+-1
+117
+-1
+231
+122
+185
+-1
+110
+54
+265
+244
+-1
+137
+81
+456
+236
+413
+77
+69
+171
+170
+-1
+387
+-1
+246
+-1
+-1
+85
+41
+-1
+-1
+413
+157
+-1
+-1
+154
+42
+260
+-1
+243
+16
+211
+-1
+141
+-1
+315
+58
+67
+253
+221
+97
+340
+326
+63
+121
+412
+288
+-1
+67
+83
+212
+392
+57
+-1
+566
+166
+123
+194
+15
+-1
+-1
+69
+-1
+250
+402
+138
+-1
+201
+116
+196
+265
+305
+204
+-1
+-1
+350
+-1
+241
+-1
+312
+407
+186
+88
+76
+136
+237
+330
+-1
+122
+71
+81
+129
+49
+92
+80
+-1
+41
+126
+-1
+148
+155
+-1
+53
+-1
+99
+130
+-1
+199
+320
+158
+134
+169
+47
+236
+-1
+36
+-1
+-1
+-1
+34
+107
+306
+425
+70
+450
+-1
+193
+41
+240
+499
+-1
+289
+279
+116
+281
+347
+262
+-1
+188
+73
+53
+45
+296
+208
+150
+-1
+98
+-1
+151
+-1
+364
+261
+358
+14
+186
+291
+104
+131
+-1
+-1
+94
+120
+22
+186
+32
+50
+152
+73
+132
+-1
+193
+87
+42
+192
+-1
+93
+-1
+65
+-1
+569
+68
+181
+94
+43
+-1
+101
+-1
+563
+171
+129
+118
+-1
+104
+-1
+365
+37
+265
+-1
+477
+-1
+293
+62
+400
+327
+64
+514
+-1
+59
+169
+87
+-1
+-1
+36
+247
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.95.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.95.txt
new file mode 100644
index 0000000..8739c3d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob0.95.txt
@@ -0,0 +1,300 @@
+78
+144
+247
+16
+131
+35
+-1
+-1
+228
+286
+-1
+219
+107
+126
+52
+111
+377
+203
+188
+61
+217
+306
+167
+208
+154
+324
+15
+338
+16
+-1
+-1
+-1
+-1
+-1
+471
+48
+440
+-1
+357
+76
+40
+159
+292
+542
+-1
+119
+97
+147
+35
+120
+115
+20
+-1
+130
+-1
+49
+66
+32
+211
+273
+115
+67
+-1
+-1
+176
+351
+332
+-1
+-1
+-1
+286
+174
+-1
+225
+-1
+168
+72
+38
+124
+-1
+125
+166
+-1
+-1
+73
+45
+-1
+-1
+276
+134
+316
+320
+37
+-1
+-1
+124
+53
+452
+417
+-1
+-1
+-1
+206
+-1
+231
+192
+327
+350
+-1
+526
+110
+-1
+76
+-1
+-1
+-1
+-1
+110
+159
+357
+269
+-1
+-1
+292
+62
+85
+557
+22
+-1
+-1
+355
+130
+57
+240
+63
+17
+114
+190
+257
+148
+103
+-1
+144
+108
+138
+-1
+487
+-1
+272
+175
+572
+48
+43
+15
+125
+49
+164
+171
+231
+91
+-1
+318
+171
+186
+137
+250
+364
+130
+113
+-1
+-1
+115
+314
+65
+534
+-1
+-1
+141
+14
+93
+201
+-1
+94
+29
+247
+-1
+235
+226
+426
+240
+141
+15
+223
+-1
+165
+77
+155
+391
+31
+246
+53
+199
+47
+543
+-1
+44
+114
+233
+208
+-1
+-1
+97
+186
+-1
+81
+216
+219
+251
+286
+134
+-1
+122
+-1
+459
+401
+14
+129
+556
+-1
+-1
+15
+-1
+-1
+346
+116
+128
+57
+152
+538
+380
+465
+118
+-1
+206
+-1
+209
+201
+400
+200
+50
+34
+483
+73
+-1
+97
+-1
+-1
+299
+82
+170
+-1
+245
+-1
+194
+44
+299
+207
+139
+-1
+446
+58
+15
+102
+165
+-1
+-1
+-1
+-1
+-1
+-1
+275
+562
+-1
+141
+-1
+207
+-1
+156
+-1
+163
+109
+139
+143
+-1
+-1
+223
+17
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob1.0.txt b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob1.0.txt
new file mode 100644
index 0000000..96eb8fe
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob1.0.txt
@@ -0,0 +1,300 @@
+61
+321
+440
+-1
+14
+-1
+99
+354
+452
+-1
+504
+32
+-1
+-1
+333
+-1
+-1
+-1
+-1
+84
+-1
+244
+77
+29
+-1
+28
+347
+212
+-1
+-1
+-1
+48
+97
+150
+-1
+-1
+-1
+-1
+164
+48
+184
+79
+251
+-1
+-1
+309
+-1
+95
+-1
+144
+-1
+201
+-1
+356
+-1
+172
+70
+440
+52
+-1
+381
+174
+36
+-1
+-1
+-1
+-1
+-1
+-1
+84
+544
+159
+-1
+189
+14
+-1
+330
+142
+539
+-1
+388
+-1
+-1
+463
+537
+92
+-1
+-1
+16
+174
+207
+-1
+-1
+291
+-1
+242
+134
+479
+15
+445
+488
+80
+290
+111
+14
+188
+110
+208
+165
+-1
+198
+195
+347
+-1
+434
+418
+-1
+126
+499
+373
+-1
+-1
+17
+-1
+353
+77
+-1
+-1
+-1
+-1
+-1
+334
+-1
+141
+-1
+190
+428
+264
+50
+180
+-1
+-1
+372
+70
+519
+-1
+-1
+93
+-1
+322
+-1
+14
+167
+-1
+-1
+101
+223
+-1
+393
+49
+-1
+574
+51
+-1
+75
+-1
+14
+119
+418
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+68
+156
+129
+-1
+417
+-1
+-1
+293
+-1
+-1
+575
+153
+-1
+21
+53
+-1
+280
+-1
+101
+511
+-1
+224
+-1
+-1
+-1
+55
+244
+-1
+476
+-1
+-1
+285
+-1
+-1
+-1
+-1
+198
+66
+-1
+16
+291
+-1
+-1
+314
+125
+-1
+253
+316
+286
+-1
+-1
+325
+406
+325
+-1
+-1
+375
+130
+139
+67
+-1
+-1
+323
+256
+220
+386
+103
+73
+14
+-1
+-1
+161
+457
+14
+170
+-1
+-1
+-1
+184
+255
+145
+67
+-1
+79
+-1
+-1
+215
+14
+338
+189
+-1
+-1
+15
+513
+-1
+48
+-1
+-1
+-1
+-1
+83
+-1
+175
+-1
+-1
+60
+-1
+183
+-1
+81
+-1
+102
+196
+-1
+60
+41
+-1
+-1
+127
+153
+284
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/docker-compose.yml b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/docker-compose.yml
new file mode 100644
index 0000000..1bed37d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/docker-compose.yml
@@ -0,0 +1,21 @@
+services:
+ major-miner:
+ build: .
+ container_name: major-miner
+ environment:
+ CORE_PERCENTAGE: 90
+ MAX_MUTATION_TRIALS: 30
+ PROB_EXTEND_TO_FREE_NEIGHBOR: 0.3
+ MAX_TOTAL: 1000
+ MAX_GENERATIONS: 600
+ PROB_REMOVE_REDUNDANCY: 0.01
+ GRID_M: 5
+ GRID_N: 5
+ POPSIZE: 6
+ K_MIN: 1
+ K_MAX: 40
+
+ volumes:
+ - type: bind
+ source: ./out
+ target: /app/out
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/evolution.py b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/evolution.py
new file mode 100644
index 0000000..baa515c
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/evolution.py
@@ -0,0 +1,117 @@
+# Move this file to src/solver to start
+# This is a file used for docker with environment variables
+
+import logging
+import multiprocessing
+import os
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+params = EvolutionParams(
+ population_size=int(os.getenv('POPSIZE', 6)),
+ max_mutation_trials=int(os.getenv('MAX_MUTATION_TRIALS', 30)),
+ mutation_extend_to_free_neighbors_probability=float(
+ os.getenv('PROB_EXTEND_TO_FREE_NEIGHBOR', 0.24)) # should be <=0.5
+)
+
+max_total = int(os.getenv('MAX_TOTAL', 100))
+max_generations = int(os.getenv('MAX_GENERATIONS', 600))
+remove_redundancy_probability = float(os.getenv('PROB_REMOVE_REDUNDANCY', 0.01))
+
+# Chimera graph
+m = int(os.getenv('GRID_M', 16)) # grid size
+n = int(os.getenv('GRID_N', 16)) # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def do_all_k_graphs():
+ for i in range(int(os.getenv('K_MIN', 6)), int(os.getenv('K_MAX', 40)) + 1):
+ print(f'Started k{i}')
+ start_time = time.time()
+ start_multiprocessing(TestGraph.k(i), f'k{i}')
+ duration = time.time() - start_time
+ print(f'Duration for k{i}: {duration}')
+
+
+def start_multiprocessing(H: UndirectedGraphAdjList, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 100)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, H), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/howManyGenerations_{m}x{n}_{max_total}_{max_generations}gen_{params.population_size}popsize_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(H: UndirectedGraphAdjList, i) -> int:
+ solver = EmbeddingSolver(H, m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ do_all_k_graphs()
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k10.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k10.txt
new file mode 100644
index 0000000..fb3128d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k10.txt
@@ -0,0 +1,100 @@
+128
+223
+356
+175
+-1
+-1
+505
+-1
+120
+-1
+-1
+73
+528
+536
+-1
+263
+290
+244
+-1
+-1
+-1
+327
+425
+-1
+-1
+597
+-1
+-1
+-1
+-1
+-1
+-1
+459
+-1
+88
+-1
+-1
+-1
+-1
+221
+194
+213
+-1
+173
+-1
+-1
+159
+371
+-1
+-1
+-1
+179
+-1
+-1
+232
+-1
+-1
+-1
+-1
+505
+-1
+376
+-1
+-1
+-1
+255
+320
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+278
+-1
+425
+441
+-1
+173
+392
+-1
+381
+155
+349
+-1
+-1
+110
+-1
+75
+244
+234
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k11.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k11.txt
new file mode 100644
index 0000000..c1f217a
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k11.txt
@@ -0,0 +1,100 @@
+171
+307
+353
+-1
+-1
+-1
+-1
+-1
+207
+-1
+-1
+382
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+257
+359
+-1
+-1
+-1
+-1
+122
+-1
+409
+-1
+-1
+303
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+407
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+448
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+561
+587
+-1
+-1
+-1
+-1
+319
+362
+-1
+-1
+-1
+-1
+-1
+349
+-1
+-1
+-1
+-1
+-1
+296
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k12.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k12.txt
new file mode 100644
index 0000000..d3cd83d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k12.txt
@@ -0,0 +1,100 @@
+400
+-1
+578
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+489
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+371
+-1
+-1
+-1
+-1
+-1
+-1
+345
+-1
+-1
+-1
+-1
+-1
+479
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+172
+531
+-1
+297
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+484
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+499
+-1
+-1
+-1
+439
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k13.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k13.txt
new file mode 100644
index 0000000..1b9e49d
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k13.txt
@@ -0,0 +1,100 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+328
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+363
+-1
+-1
+-1
+-1
+-1
+-1
+340
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+529
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+536
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k6.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k6.txt
new file mode 100644
index 0000000..f6c02a8
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k6.txt
@@ -0,0 +1,100 @@
+8
+11
+21
+13
+11
+22
+27
+9
+29
+53
+19
+12
+10
+11
+18
+38
+18
+9
+24
+30
+30
+9
+40
+30
+69
+11
+19
+23
+15
+10
+18
+17
+14
+9
+7
+10
+28
+8
+20
+22
+29
+8
+30
+19
+11
+7
+24
+59
+29
+18
+14
+92
+11
+40
+7
+15
+53
+27
+13
+9
+19
+57
+77
+15
+13
+20
+37
+8
+14
+10
+20
+35
+44
+10
+26
+28
+9
+20
+20
+7
+27
+83
+84
+20
+12
+53
+10
+8
+26
+17
+14
+24
+29
+77
+210
+62
+103
+165
+142
+326
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k7.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k7.txt
new file mode 100644
index 0000000..e8d9806
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k7.txt
@@ -0,0 +1,100 @@
+14
+25
+20
+11
+33
+81
+30
+95
+187
+158
+116
+98
+17
+39
+24
+124
+61
+22
+15
+17
+22
+38
+44
+204
+342
+26
+299
+16
+222
+23
+28
+89
+274
+315
+14
+13
+14
+42
+-1
+107
+27
+-1
+86
+18
+186
+27
+34
+127
+19
+58
+50
+-1
+62
+-1
+40
+16
+-1
+100
+44
+47
+541
+-1
+72
+13
+11
+111
+95
+56
+50
+24
+20
+12
+37
+25
+-1
+42
+23
+28
+18
+55
+111
+18
+66
+24
+13
+19
+46
+51
+56
+156
+129
+15
+76
+80
+56
+73
+160
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k8.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k8.txt
new file mode 100644
index 0000000..367af2c
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k8.txt
@@ -0,0 +1,100 @@
+34
+115
+122
+217
+155
+41
+289
+23
+68
+357
+26
+74
+599
+-1
+34
+232
+41
+82
+-1
+177
+86
+326
+20
+43
+184
+-1
+-1
+327
+-1
+321
+505
+183
+45
+355
+-1
+68
+176
+480
+425
+59
+59
+-1
+32
+131
+58
+-1
+22
+-1
+21
+-1
+20
+199
+423
+408
+-1
+206
+23
+-1
+191
+16
+32
+-1
+-1
+34
+142
+104
+19
+-1
+-1
+234
+-1
+57
+-1
+316
+48
+-1
+-1
+-1
+477
+45
+267
+-1
+-1
+15
+-1
+61
+83
+87
+39
+59
+17
+215
+63
+47
+-1
+585
+92
+-1
+276
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k9.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k9.txt
new file mode 100644
index 0000000..bc87122
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k9.txt
@@ -0,0 +1,100 @@
+61
+66
+189
+254
+224
+69
+261
+61
+-1
+-1
+158
+-1
+-1
+312
+86
+110
+-1
+126
+188
+-1
+-1
+290
+69
+-1
+106
+128
+94
+-1
+180
+-1
+188
+82
+85
+-1
+-1
+246
+-1
+-1
+198
+-1
+-1
+36
+228
+31
+64
+-1
+54
+478
+373
+-1
+-1
+-1
+563
+-1
+78
+-1
+-1
+179
+-1
+475
+108
+-1
+-1
+305
+597
+263
+-1
+271
+373
+-1
+51
+173
+40
+-1
+73
+270
+368
+-1
+238
+-1
+-1
+590
+-1
+-1
+190
+-1
+-1
+152
+178
+205
+212
+-1
+-1
+-1
+289
+209
+323
+-1
+501
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_ktimes.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_ktimes.txt
new file mode 100644
index 0000000..aed1cbb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_ktimes.txt
@@ -0,0 +1,5 @@
+CPU: i7-6700 @ 3.40 GHz (around 3.6 GHz at execution)
+4 cores, 60% used
+
+- previous data was lost (terminal closed too quickly)
+- k13: 20154.59s
\ No newline at end of file
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k15.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k15.txt
new file mode 100644
index 0000000..b16a9fb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k15.txt
@@ -0,0 +1,100 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k16.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k16.txt
new file mode 100644
index 0000000..b16a9fb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_k16.txt
@@ -0,0 +1,100 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_ktimes.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_ktimes.txt
new file mode 100644
index 0000000..2bcb5a6
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_100_600gen_6popsize_ktimes.txt
@@ -0,0 +1,35 @@
+CPU: i5-8350U @ 1.70 GHz (around 2.5 GHz at execution)
+4 cores, 100% used
+
+- K2: 3.04s
+- K3: 5.25s
+- K4: 8.83s
+- K5: 16.20s
+- K6: 20.99s
+- K7: 109.49s
+- K8: 239.84s
+- K9: 197.11s
+- K10: 98.86s
+- K11: 64.00s
+- K12: 53.02s
+- K13: 42.98s
+- K14: 58.70s
+- K15: 61.46s
+- K16: 48.78s
+- K17 failed at 64/100
+
+
+second time (80% cpu and sharing with another process)
+- K2: 4.77s
+- K3: 8.05s
+- K4: 13.13s
+- K5: 17.48s
+- K6: 29.51s
+- K7: 108.64s
+- K8: 351.69s
+- K9: 221.80s
+- K10: 107.57s
+- K11: 72.60s
+- K12: 70.01s
+- K13: 58.08s
+- K14: 59.24s
\ No newline at end of file
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k10.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k10.txt
new file mode 100644
index 0000000..122001e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k10.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k11.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k11.txt
new file mode 100644
index 0000000..122001e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k11.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k12.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k12.txt
new file mode 100644
index 0000000..122001e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k12.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k13.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k13.txt
new file mode 100644
index 0000000..122001e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k13.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k14.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k14.txt
new file mode 100644
index 0000000..122001e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k14.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k2.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k2.txt
new file mode 100644
index 0000000..c3aaa70
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k2.txt
@@ -0,0 +1,200 @@
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k3.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k3.txt
new file mode 100644
index 0000000..56baa43
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k3.txt
@@ -0,0 +1,200 @@
+1
+1
+1
+1
+1
+7
+1
+1
+1
+1
+5
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+6
+1
+12
+1
+1
+1
+5
+1
+1
+3
+6
+1
+10
+1
+3
+1
+1
+1
+5
+1
+5
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+2
+1
+1
+1
+1
+1
+1
+1
+5
+4
+7
+1
+1
+4
+1
+1
+1
+5
+1
+4
+6
+1
+1
+3
+3
+7
+5
+1
+1
+1
+1
+1
+1
+7
+1
+1
+1
+1
+3
+1
+1
+3
+1
+3
+2
+1
+11
+5
+1
+5
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+4
+4
+5
+1
+3
+7
+1
+1
+1
+1
+1
+4
+7
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+9
+1
+3
+1
+5
+6
+1
+1
+1
+3
+1
+1
+4
+1
+1
+2
+5
+1
+1
+1
+1
+1
+1
+1
+6
+1
+4
+4
+1
+4
+1
+1
+1
+1
+1
+6
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k4.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k4.txt
new file mode 100644
index 0000000..1bfb943
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k4.txt
@@ -0,0 +1,200 @@
+2
+1
+1
+1
+1
+1
+1
+2
+1
+2
+1
+1
+1
+1
+2
+1
+1
+11
+8
+1
+8
+2
+1
+1
+1
+2
+1
+1
+2
+1
+2
+9
+2
+1
+2
+8
+1
+2
+7
+7
+2
+9
+2
+1
+1
+1
+2
+2
+1
+8
+1
+15
+2
+2
+2
+1
+2
+1
+1
+3
+1
+9
+2
+3
+1
+1
+1
+9
+7
+6
+1
+2
+2
+2
+1
+1
+1
+11
+1
+1
+2
+1
+1
+2
+2
+1
+1
+2
+2
+1
+1
+1
+9
+1
+3
+3
+30
+14
+15
+11
+1
+2
+1
+2
+1
+1
+2
+14
+1
+10
+6
+3
+9
+13
+2
+1
+15
+1
+3
+2
+1
+2
+2
+2
+2
+7
+2
+1
+1
+3
+10
+6
+1
+2
+7
+6
+2
+8
+2
+1
+1
+1
+1
+3
+1
+1
+1
+2
+2
+2
+1
+2
+1
+2
+1
+10
+1
+1
+2
+1
+1
+1
+15
+8
+2
+2
+2
+3
+7
+1
+1
+7
+12
+1
+2
+7
+12
+1
+1
+3
+3
+6
+1
+1
+1
+1
+1
+8
+7
+1
+12
+2
+8
+7
+1
+3
+9
+8
+13
+11
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k5.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k5.txt
new file mode 100644
index 0000000..87aca9e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k5.txt
@@ -0,0 +1,200 @@
+2
+2
+2
+2
+10
+10
+2
+2
+16
+2
+2
+2
+2
+5
+6
+4
+3
+16
+2
+6
+2
+21
+3
+2
+37
+9
+3
+16
+18
+14
+2
+2
+20
+42
+18
+9
+7
+2
+2
+14
+35
+8
+2
+4
+2
+17
+2
+17
+2
+19
+35
+2
+7
+4
+32
+19
+9
+3
+4
+10
+11
+3
+20
+15
+2
+16
+2
+2
+11
+16
+32
+8
+2
+10
+6
+2
+15
+2
+20
+14
+38
+3
+2
+20
+2
+2
+4
+53
+2
+11
+23
+2
+2
+2
+5
+16
+17
+20
+28
+14
+2
+2
+2
+2
+2
+9
+16
+4
+2
+17
+3
+8
+16
+4
+19
+4
+2
+11
+2
+3
+2
+2
+4
+10
+7
+16
+10
+16
+9
+8
+2
+12
+7
+16
+2
+21
+13
+2
+15
+4
+4
+20
+11
+2
+5
+2
+7
+3
+13
+2
+17
+7
+58
+17
+42
+18
+20
+3
+2
+10
+3
+13
+6
+2
+15
+2
+11
+17
+2
+8
+3
+21
+14
+13
+8
+2
+2
+11
+3
+2
+2
+2
+18
+9
+19
+2
+30
+2
+14
+2
+9
+2
+13
+2
+20
+18
+3
+17
+20
+23
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k6.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k6.txt
new file mode 100644
index 0000000..3bb0d8f
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k6.txt
@@ -0,0 +1,200 @@
+7
+9
+8
+15
+18
+26
+23
+15
+21
+11
+15
+30
+10
+45
+7
+21
+11
+13
+8
+13
+13
+8
+13
+13
+34
+16
+11
+25
+12
+10
+13
+9
+27
+17
+24
+18
+30
+44
+33
+12
+10
+11
+21
+22
+14
+17
+24
+19
+30
+52
+7
+8
+14
+17
+19
+14
+7
+14
+21
+9
+30
+30
+21
+12
+18
+8
+17
+11
+7
+7
+18
+26
+14
+8
+16
+13
+8
+9
+13
+18
+7
+19
+24
+15
+31
+15
+12
+10
+17
+9
+7
+16
+14
+17
+21
+23
+18
+9
+14
+38
+14
+13
+12
+14
+9
+26
+13
+23
+19
+12
+9
+27
+9
+25
+9
+7
+15
+31
+19
+9
+26
+9
+18
+8
+18
+33
+11
+19
+11
+11
+56
+16
+13
+20
+17
+32
+19
+9
+19
+10
+12
+17
+18
+9
+13
+8
+12
+7
+11
+32
+11
+22
+10
+25
+30
+30
+7
+15
+7
+8
+15
+24
+20
+19
+22
+10
+9
+11
+19
+24
+11
+25
+15
+21
+18
+7
+9
+16
+25
+12
+13
+44
+10
+13
+9
+11
+22
+11
+26
+10
+9
+13
+12
+12
+8
+29
+8
+9
+22
+23
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k7.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k7.txt
new file mode 100644
index 0000000..89bb5a1
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k7.txt
@@ -0,0 +1,200 @@
+19
+22
+31
+-1
+21
+42
+-1
+23
+15
+15
+50
+19
+22
+26
+21
+17
+36
+43
+-1
+53
+28
+20
+18
+28
+54
+87
+25
+17
+30
+11
+20
+27
+17
+49
+16
+-1
+11
+24
+12
+36
+14
+23
+30
+18
+13
+46
+22
+17
+13
+26
+21
+17
+16
+13
+22
+12
+-1
+29
+23
+15
+113
+17
+-1
+43
+18
+23
+22
+12
+24
+35
+-1
+-1
+-1
+20
+57
+16
+27
+27
+13
+14
+35
+31
+31
+66
+22
+17
+36
+26
+20
+21
+15
+28
+21
+29
+27
+23
+-1
+-1
+-1
+-1
+10
+14
+18
+13
+28
+25
+26
+12
+24
+19
+39
+71
+28
+17
+16
+17
+16
+15
+16
+48
+35
+16
+29
+47
+28
+15
+11
+29
+19
+56
+55
+37
+25
+27
+26
+56
+41
+16
+27
+15
+45
+16
+27
+22
+16
+26
+20
+19
+32
+17
+21
+41
+19
+23
+19
+19
+21
+45
+28
+20
+18
+33
+24
+110
+21
+48
+72
+-1
+18
+45
+22
+23
+16
+45
+13
+29
+23
+45
+20
+42
+18
+16
+19
+32
+16
+57
+14
+20
+14
+30
+20
+30
+27
+13
+26
+27
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k8.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k8.txt
new file mode 100644
index 0000000..c3f4643
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k8.txt
@@ -0,0 +1,200 @@
+27
+18
+28
+-1
+-1
+-1
+-1
+220
+-1
+-1
+-1
+-1
+27
+-1
+24
+-1
+-1
+-1
+-1
+-1
+16
+-1
+19
+16
+-1
+-1
+-1
+25
+-1
+-1
+15
+34
+-1
+-1
+69
+16
+-1
+-1
+-1
+14
+39
+-1
+30
+24
+22
+267
+-1
+-1
+-1
+-1
+-1
+26
+-1
+34
+-1
+-1
+-1
+51
+-1
+61
+32
+-1
+-1
+-1
+19
+37
+23
+22
+55
+-1
+25
+-1
+-1
+27
+-1
+40
+-1
+-1
+21
+19
+38
+36
+-1
+15
+-1
+20
+-1
+26
+23
+24
+-1
+-1
+-1
+44
+-1
+36
+-1
+-1
+-1
+-1
+23
+25
+34
+-1
+-1
+-1
+-1
+32
+-1
+-1
+67
+31
+-1
+-1
+30
+-1
+-1
+-1
+-1
+15
+24
+29
+25
+38
+-1
+-1
+-1
+21
+29
+27
+-1
+59
+-1
+24
+21
+19
+22
+-1
+-1
+-1
+-1
+-1
+25
+17
+-1
+-1
+-1
+-1
+25
+-1
+48
+-1
+22
+-1
+-1
+15
+36
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+40
+22
+-1
+14
+-1
+29
+26
+-1
+31
+-1
+23
+-1
+22
+-1
+-1
+-1
+33
+23
+35
+25
+20
+-1
+-1
+30
+20
+-1
+-1
+29
+131
+24
+19
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k9.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k9.txt
new file mode 100644
index 0000000..9ec5fdb
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_2x2_200_600gen_6popsize_k9.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+35
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+18
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+21
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+19
+-1
+-1
+-1
+30
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k10.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k10.txt
new file mode 100644
index 0000000..674ebd4
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k10.txt
@@ -0,0 +1,200 @@
+92
+226
+139
+329
+-1
+-1
+-1
+-1
+-1
+206
+468
+-1
+88
+-1
+-1
+-1
+-1
+-1
+-1
+349
+-1
+-1
+-1
+156
+-1
+-1
+293
+-1
+90
+356
+-1
+409
+254
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+176
+247
+125
+69
+-1
+-1
+-1
+-1
+104
+-1
+-1
+-1
+168
+-1
+-1
+-1
+387
+-1
+-1
+-1
+-1
+-1
+-1
+393
+-1
+-1
+449
+327
+-1
+178
+208
+-1
+558
+75
+232
+346
+-1
+273
+223
+387
+-1
+-1
+-1
+333
+-1
+-1
+302
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+196
+-1
+-1
+-1
+-1
+194
+123
+138
+283
+174
+-1
+-1
+-1
+-1
+139
+-1
+-1
+301
+121
+269
+-1
+160
+-1
+167
+-1
+360
+55
+-1
+-1
+-1
+-1
+-1
+-1
+296
+-1
+306
+-1
+-1
+589
+74
+-1
+-1
+-1
+274
+142
+-1
+-1
+371
+197
+-1
+188
+304
+-1
+-1
+-1
+204
+63
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+461
+60
+-1
+468
+-1
+301
+-1
+-1
+351
+154
+-1
+304
+-1
+104
+558
+486
+-1
+230
+-1
+368
+-1
+-1
+-1
+101
+272
+-1
+-1
+-1
+-1
+248
+-1
+243
+391
+-1
+-1
+586
+561
+260
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k11.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k11.txt
new file mode 100644
index 0000000..ed6c8d9
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k11.txt
@@ -0,0 +1,200 @@
+418
+-1
+-1
+-1
+-1
+-1
+-1
+533
+-1
+411
+-1
+-1
+-1
+273
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+223
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+453
+-1
+-1
+-1
+-1
+-1
+485
+-1
+-1
+366
+284
+-1
+-1
+368
+161
+-1
+-1
+345
+-1
+130
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+325
+-1
+-1
+366
+-1
+-1
+-1
+-1
+-1
+336
+-1
+117
+-1
+-1
+-1
+-1
+94
+-1
+-1
+-1
+-1
+-1
+-1
+197
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+410
+-1
+-1
+168
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+537
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+110
+-1
+-1
+402
+466
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+365
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+156
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+143
+-1
+370
+-1
+-1
+325
+-1
+-1
+285
+-1
+433
+-1
+-1
+590
+-1
+-1
+-1
+-1
+561
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+540
+-1
+-1
+143
+-1
+389
+-1
+378
+-1
+-1
+-1
+107
+-1
+-1
+290
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k12.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k12.txt
new file mode 100644
index 0000000..82ede9f
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k12.txt
@@ -0,0 +1,200 @@
+253
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+263
+305
+-1
+-1
+-1
+-1
+339
+-1
+-1
+-1
+-1
+275
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+286
+-1
+-1
+-1
+-1
+294
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+221
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+524
+572
+-1
+547
+-1
+478
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+473
+363
+-1
+-1
+-1
+-1
+-1
+358
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+293
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+578
+-1
+-1
+502
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+291
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+333
+-1
+-1
+204
+-1
+-1
+-1
+555
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k13.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k13.txt
new file mode 100644
index 0000000..1efcf13
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k13.txt
@@ -0,0 +1,200 @@
+333
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+269
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+384
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+312
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+292
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+348
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+580
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+461
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+441
+522
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k14.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k14.txt
new file mode 100644
index 0000000..72c5c2e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k14.txt
@@ -0,0 +1,200 @@
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+478
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+333
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+521
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k2.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k2.txt
new file mode 100644
index 0000000..c3aaa70
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k2.txt
@@ -0,0 +1,200 @@
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
+0
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k3.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k3.txt
new file mode 100644
index 0000000..f79159e
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k3.txt
@@ -0,0 +1,200 @@
+1
+1
+1
+1
+1
+1
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+3
+4
+1
+1
+1
+1
+1
+5
+9
+1
+3
+2
+1
+4
+4
+1
+1
+1
+1
+8
+1
+14
+3
+1
+1
+4
+1
+8
+1
+1
+1
+1
+5
+1
+1
+3
+1
+1
+1
+1
+1
+1
+15
+1
+1
+4
+1
+4
+1
+1
+1
+4
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+5
+1
+1
+1
+3
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+24
+4
+1
+14
+27
+2
+1
+1
+1
+1
+3
+1
+1
+3
+1
+5
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+6
+1
+1
+3
+8
+4
+1
+1
+1
+10
+1
+3
+1
+1
+1
+1
+1
+1
+3
+1
+15
+10
+3
+17
+4
+1
+1
+1
+1
+1
+1
+1
+7
+1
+1
+1
+1
+1
+1
+1
+1
+4
+1
+1
+1
+1
+3
+6
+1
+3
+1
+1
+1
+5
+1
+1
+1
+1
+1
+1
+3
+1
+7
+5
+1
+1
+1
+5
+3
+3
+5
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k4.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k4.txt
new file mode 100644
index 0000000..0f8e6a3
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k4.txt
@@ -0,0 +1,200 @@
+1
+1
+2
+1
+1
+1
+2
+1
+1
+2
+1
+1
+2
+1
+1
+8
+2
+16
+1
+1
+11
+10
+1
+2
+1
+4
+1
+1
+1
+1
+2
+1
+1
+1
+1
+38
+11
+28
+42
+18
+10
+8
+1
+1
+2
+1
+2
+1
+1
+9
+1
+2
+1
+1
+1
+2
+2
+2
+1
+3
+2
+40
+1
+3
+13
+1
+1
+1
+1
+3
+38
+2
+1
+11
+25
+10
+1
+7
+3
+8
+2
+2
+8
+34
+28
+27
+1
+11
+1
+1
+1
+1
+1
+2
+2
+2
+9
+10
+77
+60
+1
+2
+1
+1
+2
+1
+2
+2
+1
+1
+2
+1
+1
+1
+1
+1
+1
+3
+4
+9
+11
+1
+1
+1
+1
+1
+2
+14
+2
+1
+10
+1
+1
+2
+15
+2
+1
+1
+1
+3
+1
+1
+1
+1
+9
+2
+1
+15
+1
+24
+3
+1
+1
+6
+13
+1
+1
+13
+2
+19
+2
+15
+17
+1
+5
+2
+9
+16
+39
+11
+2
+2
+1
+3
+2
+1
+2
+1
+1
+4
+1
+1
+1
+1
+2
+2
+1
+3
+2
+1
+11
+1
+10
+1
+74
+79
+13
+44
+14
+36
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k5.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k5.txt
new file mode 100644
index 0000000..5c55281
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k5.txt
@@ -0,0 +1,200 @@
+2
+5
+7
+12
+17
+21
+10
+23
+12
+18
+2
+34
+2
+3
+4
+2
+2
+2
+5
+2
+2
+4
+3
+3
+5
+14
+4
+63
+5
+2
+2
+2
+2
+23
+2
+8
+4
+19
+2
+2
+2
+2
+22
+3
+41
+8
+12
+26
+5
+2
+9
+2
+2
+2
+9
+5
+8
+21
+2
+3
+78
+6
+12
+2
+2
+2
+44
+2
+2
+26
+8
+2
+99
+7
+6
+9
+75
+26
+6
+15
+2
+2
+2
+18
+26
+15
+2
+2
+2
+25
+2
+3
+2
+7
+4
+17
+12
+6
+24
+39
+2
+2
+2
+2
+4
+8
+6
+2
+10
+7
+2
+2
+17
+2
+18
+18
+6
+3
+2
+2
+16
+2
+34
+2
+7
+2
+2
+18
+2
+15
+46
+2
+2
+2
+2
+7
+2
+7
+2
+13
+7
+59
+29
+2
+2
+4
+26
+2
+2
+16
+2
+17
+6
+36
+19
+15
+18
+31
+2
+6
+5
+2
+2
+2
+18
+2
+75
+9
+2
+2
+3
+14
+23
+17
+25
+2
+2
+42
+55
+19
+2
+3
+2
+12
+5
+67
+17
+2
+2
+2
+2
+30
+2
+9
+6
+37
+17
+26
+229
+181
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k6.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k6.txt
new file mode 100644
index 0000000..79e3113
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k6.txt
@@ -0,0 +1,200 @@
+11
+15
+25
+16
+17
+28
+9
+17
+34
+19
+19
+19
+34
+15
+51
+8
+11
+48
+126
+9
+23
+11
+13
+9
+115
+139
+21
+42
+9
+17
+16
+21
+9
+16
+8
+51
+110
+25
+19
+12
+16
+25
+34
+22
+24
+28
+14
+18
+13
+39
+36
+19
+15
+16
+56
+44
+9
+18
+11
+35
+9
+23
+9
+29
+14
+8
+24
+36
+36
+22
+53
+23
+22
+61
+26
+17
+10
+9
+7
+10
+95
+8
+18
+31
+10
+7
+16
+7
+8
+25
+42
+27
+26
+7
+40
+47
+19
+25
+60
+139
+10
+11
+7
+29
+22
+28
+24
+42
+47
+18
+14
+42
+10
+32
+25
+12
+17
+8
+7
+16
+13
+21
+33
+39
+25
+84
+36
+10
+9
+18
+60
+36
+7
+10
+95
+33
+18
+38
+36
+18
+57
+45
+59
+190
+19
+46
+12
+33
+8
+47
+23
+9
+18
+9
+9
+14
+10
+24
+33
+13
+10
+12
+10
+38
+29
+15
+23
+31
+56
+59
+21
+25
+23
+7
+9
+43
+17
+35
+25
+9
+28
+26
+68
+15
+21
+19
+30
+24
+11
+62
+113
+21
+15
+19
+26
+121
+185
+198
+175
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k7.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k7.txt
new file mode 100644
index 0000000..4b07dc3
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k7.txt
@@ -0,0 +1,200 @@
+19
+23
+29
+68
+95
+46
+11
+14
+25
+84
+34
+170
+186
+43
+75
+14
+115
+178
+35
+18
+46
+114
+13
+91
+26
+241
+-1
+29
+22
+35
+-1
+-1
+497
+19
+64
+153
+46
+134
+22
+11
+105
+88
+19
+40
+14
+52
+20
+34
+149
+11
+77
+25
+15
+87
+-1
+43
+159
+24
+20
+56
+111
+17
+88
+168
+11
+22
+29
+347
+400
+31
+102
+62
+19
+69
+85
+89
+21
+111
+302
+126
+25
+333
+111
+21
+80
+65
+202
+22
+67
+29
+24
+38
+17
+-1
+35
+32
+66
+156
+-1
+-1
+22
+23
+33
+73
+53
+27
+134
+100
+179
+70
+11
+24
+18
+124
+26
+178
+12
+10
+34
+12
+191
+57
+24
+16
+82
+65
+228
+76
+13
+14
+107
+29
+19
+21
+95
+12
+17
+45
+19
+89
+319
+35
+165
+24
+28
+12
+17
+43
+34
+29
+39
+21
+23
+-1
+115
+29
+246
+-1
+24
+12
+11
+27
+32
+-1
+12
+27
+22
+13
+35
+14
+67
+66
+13
+205
+11
+22
+174
+19
+125
+20
+-1
+12
+-1
+52
+377
+440
+59
+126
+71
+46
+22
+27
+42
+122
+74
+108
+388
+-1
+-1
+501
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k8.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k8.txt
new file mode 100644
index 0000000..34c9410
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k8.txt
@@ -0,0 +1,200 @@
+35
+51
+52
+50
+34
+52
+158
+155
+304
+-1
+-1
+17
+-1
+245
+-1
+71
+80
+161
+-1
+147
+-1
+26
+16
+19
+-1
+47
+169
+152
+151
+36
+340
+99
+-1
+88
+69
+-1
+55
+196
+140
+22
+-1
+82
+120
+88
+48
+35
+232
+94
+127
+24
+270
+238
+183
+206
+27
+33
+193
+32
+92
+386
+150
+-1
+400
+32
+73
+52
+-1
+238
+-1
+204
+165
+63
+94
+-1
+152
+-1
+-1
+230
+257
+-1
+-1
+266
+42
+73
+61
+79
+-1
+105
+286
+87
+311
+26
+-1
+81
+-1
+533
+-1
+468
+569
+-1
+19
+19
+48
+44
+129
+208
+65
+22
+146
+42
+21
+52
+122
+390
+22
+-1
+48
+506
+-1
+51
+42
+274
+-1
+57
+135
+56
+139
+391
+17
+129
+369
+149
+98
+62
+62
+15
+14
+19
+-1
+308
+-1
+51
+228
+-1
+45
+175
+-1
+88
+-1
+183
+-1
+82
+24
+44
+319
+44
+-1
+101
+32
+38
+88
+200
+221
+33
+280
+17
+287
+149
+130
+421
+56
+139
+58
+41
+16
+44
+337
+-1
+176
+62
+103
+147
+136
+40
+335
+72
+102
+353
+14
+265
+66
+141
+-1
+-1
+333
+102
+236
+292
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k9.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k9.txt
new file mode 100644
index 0000000..466e594
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_k9.txt
@@ -0,0 +1,200 @@
+216
+362
+385
+67
+-1
+-1
+171
+198
+-1
+156
+-1
+-1
+67
+76
+83
+105
+-1
+296
+145
+302
+128
+226
+153
+-1
+225
+109
+109
+-1
+478
+-1
+98
+68
+165
+40
+-1
+97
+78
+124
+-1
+-1
+-1
+379
+-1
+63
+-1
+56
+146
+94
+-1
+-1
+75
+62
+-1
+127
+-1
+169
+-1
+54
+137
+253
+-1
+88
+423
+-1
+-1
+138
+-1
+-1
+-1
+37
+261
+353
+121
+-1
+98
+54
+-1
+95
+-1
+97
+117
+-1
+149
+50
+167
+-1
+360
+226
+118
+358
+482
+60
+49
+134
+228
+72
+-1
+-1
+580
+-1
+62
+209
+317
+157
+324
+210
+262
+-1
+-1
+-1
+-1
+76
+57
+270
+204
+203
+-1
+129
+-1
+228
+75
+-1
+-1
+-1
+-1
+240
+-1
+166
+96
+-1
+-1
+211
+-1
+-1
+96
+53
+-1
+443
+-1
+136
+-1
+51
+191
+-1
+312
+-1
+112
+-1
+-1
+-1
+75
+-1
+445
+-1
+278
+216
+-1
+64
+202
+412
+68
+-1
+-1
+47
+208
+163
+-1
+41
+109
+133
+-1
+177
+-1
+-1
+-1
+-1
+109
+326
+208
+109
+373
+71
+370
+215
+-1
+215
+-1
+-1
+154
+38
+160
+293
+111
+47
+-1
+203
+204
+-1
+-1
+-1
diff --git a/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_ktimes.txt b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_ktimes.txt
new file mode 100644
index 0000000..f2b53f7
--- /dev/null
+++ b/python/plots/how_many_generations/data_after_bug_fix/k_graphs/howManyGenerations_5x5_200_600gen_6popsize_ktimes.txt
@@ -0,0 +1,26 @@
+CPU: i7-6700 @ 3.40 GHz (around 3.6 GHz at execution)
+4 cores, 60% used
+
+- K2: 5.46s
+- K3: 23.17s
+- K4: 54.17s
+- K5: 100.35s
+- unknown
+
+
+CPU: i5-8350U @ 1.70 GHz (around 2.5 GHz at execution)
+4 cores, 80% used
+
+- K2: 3.13s
+- K3: 11.70s
+- K4: 44.09s
+- K5: 108.74s
+- K6: 232.39s
+- K7: 521.61s
+- K8: 3722.22s
+- K9: 1655.97s
+- K10: 2720.19s
+- K11: 3210.61s
+- K12: 3686.02s
+- K13: 3449.03s
+- K14: 4362.36s
diff --git a/python/plots/how_many_generations/evolution.py b/python/plots/how_many_generations/evolution.py
new file mode 100644
index 0000000..151e8f8
--- /dev/null
+++ b/python/plots/how_many_generations/evolution.py
@@ -0,0 +1,116 @@
+# Move this file to src/solver to start
+
+import logging
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+# Params used to generate "how_many_generations_nikolaus_10000"
+# population_size=12
+# max_mutation_trials=30
+# mutation_extend_to_free_neighbors_probability=0.3
+# max_total = 10000
+# max_generations = 100
+# remove_redundancy_probability = 0.01
+# m = 2 # grid size
+# n = 2 # grid size
+# t = 4 # shore size
+
+params = EvolutionParams(
+ population_size=12,
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3 # should be <=0.5
+)
+
+max_total = 10000
+max_generations = 100
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 2 # grid size
+n = 2 # grid size
+t = 4 # shore size
+
+
+################################ Setup ########################################
+
+H = TestGraph.crossed_house()
+
+
+############################### Evolution ######################################
+
+def main_loop():
+ with open('./out/how_many_generations.txt', 'w') as f:
+ for i in tqdm(range(max_total)):
+ logger.info('')
+ logger.info('#############')
+ logger.info('🎈 NEW MAIN 🎈')
+ logger.info('#############')
+ logger.info('')
+ logger.info(f'Calling main: {i}')
+
+ generations_needed = main()
+ f.write(str(generations_needed) + '\n')
+
+
+def main() -> int:
+ solver = EmbeddingSolver(H, m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ main_loop()
diff --git a/python/plots/how_many_generations/evolution_different_grid_sizes.py b/python/plots/how_many_generations/evolution_different_grid_sizes.py
new file mode 100644
index 0000000..56eed06
--- /dev/null
+++ b/python/plots/how_many_generations/evolution_different_grid_sizes.py
@@ -0,0 +1,115 @@
+# Move this file to src/solver to start
+
+import logging
+import multiprocessing
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+params = EvolutionParams(
+ population_size=12,
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3 # should be <=0.5
+)
+
+max_total = 100
+max_generations = 100
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def different_grid_sizes():
+ for m in range(9, 10):
+ print(f'Started with grid size {m}x{m}')
+
+ graph = TestGraph.k(8)
+ params = [graph, m]
+
+ start_time = time.time()
+ start_multiprocessing(params, 'k8_different_grid_sizes')
+ duration = time.time() - start_time
+ print(f'Duration for grid size {m}x{m}: {duration} s')
+
+
+def start_multiprocessing(params, name: str):
+ with multiprocessing.Pool() as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/how_many_generations_{params[1]}x{params[1]}_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(params, j) -> int:
+ solver = EmbeddingSolver(params[0], params[1], params[1], t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ different_grid_sizes()
diff --git a/python/plots/how_many_generations/evolution_different_population_sizes.py b/python/plots/how_many_generations/evolution_different_population_sizes.py
new file mode 100644
index 0000000..bc8864b
--- /dev/null
+++ b/python/plots/how_many_generations/evolution_different_population_sizes.py
@@ -0,0 +1,115 @@
+# Move this file to src/solver to start
+
+import logging
+import multiprocessing
+import os
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+max_total = 100
+max_generations = 600
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def different_params():
+ for population_size in range(1, 21):
+ print(f'Started population size {population_size}')
+ graph = TestGraph.k(8)
+ start_time = time.time()
+ start_multiprocessing((graph, population_size), f'k8_population_size_{population_size}')
+ duration = time.time() - start_time
+ print(f'Duration for population size {population_size}: {duration} s')
+
+
+def start_multiprocessing(plot_params, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 75)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, plot_params), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/how_many_generations_{m}x{n}_1000_600_max_gen_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(plot_params, j) -> int:
+ solver = EmbeddingSolver(plot_params[0], m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver, plot_params)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver, plot_params) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ evo_params = EvolutionParams(
+ population_size=plot_params[1],
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3 # should be <=0.5
+ )
+
+ child = solver.generate_population_and_select(evo_params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ different_params()
diff --git a/python/plots/how_many_generations/evolution_multiprocessing.py b/python/plots/how_many_generations/evolution_multiprocessing.py
new file mode 100644
index 0000000..381716b
--- /dev/null
+++ b/python/plots/how_many_generations/evolution_multiprocessing.py
@@ -0,0 +1,113 @@
+# Move this file to src/solver to start
+
+import logging
+import multiprocessing
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+params = EvolutionParams(
+ population_size=12,
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3 # should be <=0.5
+)
+
+max_total = 1000
+max_generations = 100
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 5 # grid size
+n = 5 # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def do_all_k_graphs():
+ for i in range(5, 13):
+ print(f'Started k{i}')
+ start_time = time.time()
+ start_multiprocessing(TestGraph.k(i), f'k{i}')
+ duration = time.time() - start_time
+ print(f'Duration for k{i}: {duration} s')
+
+
+def start_multiprocessing(H: UndirectedGraphAdjList, name: str):
+ with multiprocessing.Pool() as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, H), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/how_many_generations_{m}x{n}_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(H: UndirectedGraphAdjList, i) -> int:
+ solver = EmbeddingSolver(H, m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ do_all_k_graphs()
diff --git a/python/plots/how_many_generations/evolution_multiprocessing_env.py b/python/plots/how_many_generations/evolution_multiprocessing_env.py
new file mode 100644
index 0000000..31e9c9b
--- /dev/null
+++ b/python/plots/how_many_generations/evolution_multiprocessing_env.py
@@ -0,0 +1,117 @@
+# Move this file to src/solver to start
+# This is a file used for docker with environment variables
+
+import logging
+import multiprocessing
+import os
+import time
+from functools import partial
+from random import random
+from typing import Optional
+
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+from tqdm import tqdm
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+
+################################# Params #######################################
+
+params = EvolutionParams(
+ population_size=int(os.getenv('POPULATION_SIZE', 4)),
+ max_mutation_trials=int(os.getenv('MAX_MUTATION_TRIALS', 30)),
+ mutation_extend_to_free_neighbors_probability=int(
+ os.getenv('PROB_EXTEND_TO_FREE_NEIGHBOR', 0.11)) # should be <=0.5
+)
+
+max_total = int(os.getenv('MAX_TOTAL', 1000))
+max_generations = int(os.getenv('MAX_GENERATIONS', 600))
+remove_redundancy_probability = int(os.getenv('PROB_REMOVE_REDUNDANCY', 0.01))
+
+# Chimera graph
+m = int(os.getenv('GRID_M', 5)) # grid size
+n = int(os.getenv('GRID_N', 5)) # grid size
+t = 4 # shore size
+
+
+############################### Evolution ######################################
+
+def do_all_k_graphs():
+ for i in range(int(os.getenv('K_MIN', 5)), int(os.getenv('K_MAX', 30)) + 1):
+ print(f'Started k{i}')
+ start_time = time.time()
+ start_multiprocessing(TestGraph.k(i), f'k{i}')
+ duration = time.time() - start_time
+ print(f'Duration for k{i}: {duration}')
+
+
+def start_multiprocessing(H: UndirectedGraphAdjList, name: str):
+ processes = multiprocessing.cpu_count() * int(os.getenv('CORE_PERCENTAGE', 90)) // 100
+ with multiprocessing.Pool(processes) as pool:
+ # Multiprocessing
+ res = list(tqdm(
+ pool.imap_unordered(partial(do_once, H), range(max_total)),
+ total=max_total)
+ )
+
+ # Save to file
+ with open(f'./out/howManyGenerations_{m}x{n}_{max_total}_{max_generations}gen_{params.population_size}popsize_{name}.txt', 'w') as f:
+ for generations_needed in res:
+ f.write(str(generations_needed) + '\n')
+
+
+def do_once(H: UndirectedGraphAdjList, i) -> int:
+ solver = EmbeddingSolver(H, m, n, t)
+
+ # --- Init
+ solver.initialize_embedding()
+
+ if solver.found_embedding():
+ print('🎉 Directly found embedding after initialization')
+ return 0
+
+ # --- Start solver
+ for i in range(max_generations):
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return -1
+
+ solver.commit(child)
+
+ # Check if done
+ if child.is_valid_embedding():
+ child.remove_redundancy()
+ return i+1
+ else:
+ logger.info('✅ Generation passed')
+
+ return -1
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Main ##########################################
+
+
+if __name__ == "__main__":
+ do_all_k_graphs()
diff --git a/python/plots/how_many_generations/how_many_embedded.py b/python/plots/how_many_generations/how_many_embedded.py
new file mode 100644
index 0000000..61f6d46
--- /dev/null
+++ b/python/plots/how_many_generations/how_many_embedded.py
@@ -0,0 +1,63 @@
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+import numpy as np
+
+names = [str(i) for i in range(1, 8)]
+embedded = []
+average_generations = []
+
+# --- Prepare data
+for name in names:
+ filename = f'./data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize{name}.txt'
+ with open(filename, 'r') as f:
+ data = f.read().splitlines()
+ data = [int(value) for value in data]
+ # unique, counts = np.unique(data, return_counts=True)
+ embedded.append(100 - data.count(-1))
+
+ data_embedded = [value for value in data if value != -1]
+ average_generations.append(np.average(data_embedded))
+
+
+# --- Plot setup
+plt.rcParams.update({
+ "text.usetex": True,
+ "font.family": "Helvetica"
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 14
+BIGGER_SIZE = 16
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+# --- Plot
+color = '#E53054'
+fig, ax = plt.subplots(figsize=(10, 6))
+ax.set_ylabel('Occurrences of valid embeddings')
+ax.set_xlabel('Probability of using the "extend to free neighbor" mutation')
+ax.set_ylim(0, 100)
+# ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
+# ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
+ax.plot(names, embedded, color, marker='o')
+
+# Write average number of generations needed next to data point
+# https://queirozf.com/entries/add-labels-and-text-to-matplotlib-plots-annotation-examples
+for i, v in enumerate(average_generations):
+ ax.annotate(str(round(v, 0)),
+ (i, embedded[i]),
+ textcoords='offset points',
+ xytext=(0, -22),
+ horizontalalignment='center')
+
+# ax.set_title('Generations needed for the crossed house puzzle')
+plt.tight_layout()
+plt.show()
diff --git a/python/plots/how_many_generations/how_many_embedded_and_generations.py b/python/plots/how_many_generations/how_many_embedded_and_generations.py
new file mode 100644
index 0000000..d6c9d4a
--- /dev/null
+++ b/python/plots/how_many_generations/how_many_embedded_and_generations.py
@@ -0,0 +1,106 @@
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+import numpy as np
+
+names = [str(i) for i in range(2, 15)]
+# names = np.linspace(0.0, 1.0, num=20)
+# names = [str(round(v, 2)) for v in names]
+# names.append('0.22')
+# names.append('0.24')
+# names.append('0.27')
+# names.append('0.29')
+# names.append('0.31')
+# names.append('0.33')
+# names.append('0.36')
+# names.append('0.38')
+# names.append('0.4')
+
+embedded = []
+average_generations = []
+max_total = 300
+
+# --- Prepare data
+for name in names:
+ # filename = f'./data_after_bug_fix/k8_popsize/howManyGenerations_5x5_10_600gen_k8popsize{name}.txt'
+ # filename = f'./data_after_bug_fix/k8_probabilities_free/howManyGenerations_5x5_20_600gen_k80.0-0.2prob{name}.txt'
+ # filename = f'./data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k{name}.txt'
+ # filename = f'./data_after_bug_fix/k8_probabilities_free/server-run/howManyGenerations_5x5_300_600gen_k8prob{name}.txt'
+ filename = f'./data_after_bug_fix/k8_popsize/server-run/howManyGenerations_5x5_300_600gen_k8popsize{name}.txt'
+ with open(filename, 'r') as f:
+ data = f.read().splitlines()
+ data = [int(value) for value in data]
+ # unique, counts = np.unique(data, return_counts=True)
+ embedded.append(max_total - data.count(-1))
+
+ data_embedded = [value for value in data if value != -1]
+ average_generations.append(np.average(data_embedded))
+
+
+# --- Plot setup
+plt.rcParams.update({
+ "text.usetex": True,
+ "font.family": "Helvetica"
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 14
+BIGGER_SIZE = 16
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+# --- Plot
+fig, ax = plt.subplots(figsize=(11, 6))
+ax.set_xlabel('Population size')
+# ax.set_xlabel('Probability for "extend to free neighbors" heuristic')
+# ax.set_xlabel('K graph')
+
+# Average generations
+color_blue = '#2981B3'
+# color_blue = '#2EB4FF'
+ax.set_ylabel('Average number of generations needed', color=color_blue)
+# ax.plot(names, average_generations, color=color_blue, marker='o')
+ax.bar(names, average_generations, color=color_blue, fill=False, edgecolor=color_blue)
+ax.tick_params(axis='y', labelcolor=color_blue)
+
+
+ax2 = ax.twinx()
+# Number embedded
+color_red = '#E53054'
+# color_red = '#FF4A6D'
+ax2.set_ylabel('Occurrences of valid embeddings', color=color_red)
+ax2.set_ylim(0, max_total+5)
+# ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
+# ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
+ax2.plot(names, embedded, color=color_red, marker='o')
+ax2.tick_params(axis='y', labelcolor=color_red)
+
+
+# Write average number of generations needed next to data point
+# https://queirozf.com/entries/add-labels-and-text-to-matplotlib-plots-annotation-examples
+for i, embedded_count in enumerate(embedded):
+ percent_embedded = round(embedded_count / max_total * 100, 2)
+ ax2.annotate(f'{percent_embedded}\,\%',
+ (i, embedded_count),
+ textcoords='offset points',
+ xytext=(16, 10),
+ horizontalalignment='center',
+ color=color_red,
+ fontsize=14)
+# for i, v in enumerate(average_generations):
+# ax.annotate(str(round(v, 0)),
+# (i, embedded[i]),
+# textcoords='offset points',
+# xytext=(0, -22),
+# horizontalalignment='center')
+
+# ax.set_title('Generations needed for the crossed house puzzle')
+plt.tight_layout()
+plt.show()
diff --git a/python/plots/how_many_generations/how_many_generations.py b/python/plots/how_many_generations/how_many_generations.py
new file mode 100644
index 0000000..abdaeea
--- /dev/null
+++ b/python/plots/how_many_generations/how_many_generations.py
@@ -0,0 +1,45 @@
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+import numpy as np
+
+# --- Prepare data
+with open('./data/how_many_generations_5x5_k6.txt', 'r') as f:
+ data = f.read().splitlines()
+ data = [int(value) for value in data]
+
+unique, counts = np.unique(data, return_counts=True)
+
+
+# --- Plot setup
+plt.rcParams.update({
+ "text.usetex": True,
+ "font.family": "Helvetica"
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 10
+BIGGER_SIZE = 12
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+# --- Plot
+fig, ax = plt.subplots(figsize=(10, 6))
+ax.axhline(0, color='grey', linewidth=0.8)
+ax.set_ylabel('Scores', fontsize=18)
+ax.set_ylabel('Occurrences')
+ax.set_xlabel('Generations needed', fontsize=18)
+ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
+ax.xaxis.set_minor_locator(ticker.MultipleLocator(1))
+ax.bar(unique, counts)
+
+# ax.set_title('Generations needed for the crossed house puzzle')
+plt.tight_layout()
+plt.show()
diff --git a/python/plots/how_many_generations/how_many_generations_all.py b/python/plots/how_many_generations/how_many_generations_all.py
new file mode 100644
index 0000000..3233d65
--- /dev/null
+++ b/python/plots/how_many_generations/how_many_generations_all.py
@@ -0,0 +1,104 @@
+from collections import namedtuple
+
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+import numpy as np
+
+names = [str(i) for i in range(6, 14)]
+
+
+# --- Prepare data
+Data = namedtuple('Data', ['unique', 'counts'])
+datas = []
+for name in names:
+ # filename = f'./data/population_size_100_runs/how_many_generations_5x5_100_600_max_gen_k8_population_size_{name}.txt'
+ filename = f'./data_after_bug_fix/k_graphs/howManyGenerations_16x16_100_600gen_6popsize_k{name}.txt'
+ with open(filename, 'r') as f:
+ data = f.read().splitlines()
+ data = [int(value) for value in data]
+ unique, counts = np.unique(data, return_counts=True)
+ datas.append(Data(unique, counts))
+
+
+# --- Plot setup
+plt.rcParams.update({
+ "text.usetex": True,
+ "font.family": "Helvetica"
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 14
+BIGGER_SIZE = 16
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('axes', titlesize=BIGGER_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+# plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+# --- Plot
+rows = 2
+cols = 4
+fig, axs = plt.subplots(rows, cols, figsize=(14, 9))
+
+i = 0
+for r in range(rows):
+ for c in range(cols):
+ ax = axs[r, c]
+
+ if i == len(datas):
+ break
+
+ # color = '#2981B3'
+ color = '#E53054'
+ ax.bar(datas[i][0], datas[i].counts, color=color)
+ # ax.axhline(0, color='grey', linewidth=0.8)
+ # ax.set_title(f'population size {names[i]}')
+ ax.set_title(f'$K_{{{names[i]}}}$')
+
+ # Same scale for most subfigures
+ # maximum = max(datas[i].unique)
+ # print(maximum)
+ # if maximum < 100:
+ # ax.set_xlim(-5, 100)
+
+ ax.set_xlim(left=-5)
+ if i >= 2:
+ ax.set_xlim(left=-30)
+
+ # major = 5 if max(datas[i].unique) <= 60 else 10
+ # ax.xaxis.set_major_locator(ticker.MultipleLocator(major))
+
+ # minor = 1 if max(datas[i].unique) <= 60 else 5
+ # ax.xaxis.set_minor_locator(ticker.MultipleLocator(minor))
+
+ # https://stackoverflow.com/a/38096332/9655481
+ ax.yaxis.get_major_locator().set_params(integer=True)
+ ax.xaxis.set_minor_locator(ticker.AutoMinorLocator())
+ ax.yaxis.set_minor_locator(ticker.AutoMinorLocator())
+
+ # y_max = 60 if r == 0 else 70
+ # ax.set_ylim(top=75)
+ # if max(datas[i].counts) >= 70:
+ # ax.set_ylim(top=90)
+ # else:
+ # ax.set_ylim(top=75)
+ # ax.set_xlim(0, 100)
+
+ i += 1
+
+# Label
+# axs[0, 0].set_xlim(-5, 20)
+
+axs[1, 0].set_ylabel('Occurrences')
+axs[1, 0].set_xlabel('Generations needed')
+
+# ax.set_title('Generations needed for the crossed house puzzle')
+plt.subplots_adjust(left=0.05, top=0.96, right=0.98, bottom=0.06, hspace=0.3, wspace=0.25)
+# plt.tight_layout(pad=0.2, w_pad=0.1, h_pad=0.1, rect=(0.05, 0.05, 0.95, 0.95))
+plt.show()
diff --git a/python/requirements.txt b/python/requirements.txt
new file mode 100644
index 0000000..485c755
--- /dev/null
+++ b/python/requirements.txt
@@ -0,0 +1,5 @@
+dwave-networkx==0.8.10
+matplotlib==3.4.3
+networkx==2.6.3
+numpy==1.21.0
+tqdm==4.62.3
\ No newline at end of file
diff --git a/python/src/drawing/color_util.py b/python/src/drawing/color_util.py
new file mode 100644
index 0000000..f7de6f7
--- /dev/null
+++ b/python/src/drawing/color_util.py
@@ -0,0 +1,28 @@
+def change_brightness(color, amount=1):
+ """
+ Lightens/Darkens the given color by multiplying luminosity by the given amount.
+ Input can be matplotlib color string, hex string, or RGB tuple.
+
+ Examples:
+ >> change_brightness('g', 0.3)
+ >> change_brightness('#F034A3', 0.6)
+ >> change_brightness((.3,.55,.1), 0.5)
+ """
+ # adapted from
+ # https://gist.github.com/ihincks/6a420b599f43fcd7dbd79d56798c4e5a
+ # https://stackoverflow.com/a/49601444/9655481
+
+ import colorsys
+
+ import matplotlib.colors as mc
+ import numpy as np
+
+ try:
+ c = mc.cnames[color]
+ except:
+ c = color
+
+ c = np.array(colorsys.rgb_to_hls(*mc.to_rgb(c)))
+ hls = (c[0], max(0, min(1, amount * c[1])), c[2])
+ rgb = colorsys.hls_to_rgb(*hls)
+ return mc.to_hex(rgb)
diff --git a/python/src/drawing/draw.py b/python/src/drawing/draw.py
index b46231a..bb6dba0 100644
--- a/python/src/drawing/draw.py
+++ b/python/src/drawing/draw.py
@@ -1,95 +1,137 @@
import dwave_networkx as dnx
import matplotlib.pyplot as plt
import networkx as nx
+from src.drawing.color_util import change_brightness
+from src.drawing.node_colors import get_supernode_color
+default_embedded_color = '#6B6B6A'
-class Draw():
- def __init__(self):
- self.pos = {
- 0: (0., -0.5),
- 1: (0.25, -0.5),
- 2: (0.75, -0.5),
- 3: (1, -0.5),
- 4: (0.5, 0.),
- 5: (0.5, -0.25),
- 6: (0.5, -0.75),
- 7: (0.5, -1.)
- }
- self.chain_colors = ['#55C1D9', '#F29E38',
- '#F23827', '#D748F5', '#39DBC8']
+class DrawEmbedding():
- def draw_chimera_graph(self, m, n, t):
+ def init_figure(self):
+ self.fig = plt.figure()
+ plt.subplots_adjust(left=0.0, right=1.0,
+ bottom=0.0, top=1.0,
+ wspace=0.1, hspace=0.1)
+
+ def __init__(self, m, n, t):
+ self.total_steps = 0
+
+ # https://matplotlib.org/stable/gallery/subplots_axes_and_figures/figure_size_units.html
+ self.px = 1/plt.rcParams['figure.dpi'] # pixel in inches
+ plt.rcParams.update({
+ 'axes.titlesize': 22,
+ 'text.usetex': False,
+ 'font.family': 'Helvetica'
+ })
+
+ self.col = 0
+ self.m = m
+ self.n = n
+
+ self.init_chimera_graph(m, n, t)
+
+ def init_chimera_graph(self, m, n, t):
+ self.chimera_G = dnx.chimera_graph(m, n, t)
+ self.pos_chimera = dnx.chimera_layout(self.chimera_G)
+
+ def draw_chimera_graph(self):
"""Draws a Chimera graph."""
- G = dnx.chimera_graph(m, n, t)
- pos_chimera = dnx.chimera_layout(G)
- nx.draw_networkx(G,
- pos=pos_chimera,
+
+ # Nodes & Edges
+ nx.draw_networkx(self.chimera_G,
+ pos=self.pos_chimera,
width=2,
with_labels=False,
- node_color='#858585',
- edge_color='#BABABA')
- # dnx.draw_chimera(G,
- # width=2,
- # node_color='#858585',
- # edge_color='#BABABA')
-
- def _draw(self, nodes, edges, mapping_G_to_H):
+ node_color='#C8C8C8',
+ edge_color='#C8C8C8')
+
+ # Labels
+ # Shift labels
+ pos_labels = {node: [pos[0] - 0.020, pos[1]]
+ for (node, pos) in self.pos_chimera.items()}
+ nx.draw_networkx_labels(self.chimera_G,
+ pos=pos_labels,
+ font_size=8,
+ font_color='#858585')
+
+ def draw_embedding(self, nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H):
"""Draws the embedding onto the Chimera graph.
- Arguments
- ---------
- - nodes: nodes list
- - edges: tuple (from, to, chain)
+ Args:
+ nodes (set[int]): nodes
+ edges (set[tuple[int, int, int]]): set of tuples (node1, node2, chain)
"""
labels = {}
for node in nodes:
labels[node] = mapping_G_to_H[node]
- chains = [edge[2] for edge in edges]
- for chain in range(max(chains)+1):
- chain_edges = [(edge[0], edge[1])
- for edge in edges if edge[2] == chain]
-
- graph = nx.Graph()
- graph.add_nodes_from(nodes)
- graph.add_edges_from(chain_edges)
-
- chain_color = self.chain_colors[chain % len(self.chain_colors)]
- nx.draw_networkx(graph,
- labels=labels,
- pos=self.pos,
- width=3,
- style='solid',
- node_color='#363636',
- edge_color=chain_color,
- font_color='whitesmoke',
- font_size=15,
- font_family='serif')
-
- def draw_embedding(self, nodes, edges, mapping_G_to_H):
- self._draw(nodes, edges, mapping_G_to_H)
+ G = nx.Graph()
+ G.add_nodes_from(nodes)
+
+ # Labels
+ nx.draw_networkx_labels(G,
+ pos=self.pos_chimera,
+ labels=labels,
+ font_size=14,
+ font_color='whitesmoke',
+ font_family='serif')
+
+ # Nodes & Edges
+ remember_nodes_in_chain = []
+ for edge in edges:
+ node1 = edge[0]
+ node2 = edge[1]
+
+ # Color edges inside a supernode with the same color
+ # and between supernodes with the first color
+ node1_H = mapping_G_to_H[node1]
+ node2_H = mapping_G_to_H[node2]
+
+ # Nodes
+ self.draw_node(node1, get_supernode_color(node1_H))
+ self.draw_node(node2, get_supernode_color(node2_H))
+
+ # Edges
+ G.add_edge(node1, node2)
+ chain_color = get_supernode_color(node1_H)\
+ if node1_H == node2_H else default_embedded_color
+ nx.draw_networkx_edges(G,
+ pos=self.pos_chimera,
+ width=3,
+ style='solid',
+ edge_color=chain_color)
+ G.remove_edge(node1, node2)
+
+ def draw_node(self, node: int, color):
+ G = nx.Graph()
+ G.add_node(node)
+ nx.draw_networkx_nodes(G,
+ pos=self.pos_chimera,
+ node_color=change_brightness(color, amount=0.8),
+ linewidths='2',
+ edgecolors=color)
+
+ def draw_chimera_and_embedding(self, nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H):
+ self.draw_chimera_graph()
+ self.draw_embedding(nodes, edges, mapping_G_to_H)
+
+ def show_embedding(self):
plt.show()
- ############################ Big Plot ######################################
+ ############################ Embedding step ################################
- def init_big_plot(self, row_count):
- self.big_plot_row_count = row_count
- # https://matplotlib.org/stable/gallery/subplots_axes_and_figures/figure_size_units.html
- px = 1/plt.rcParams['figure.dpi'] # pixel in inches
- fig = plt.figure(figsize=(row_count*200*px*3, row_count*200*px*3))
- plt.axis('off')
- plt.subplots_adjust(left=0.0, right=1.0, bottom=0.0, top=1.0,
- wspace=0.0, hspace=0.0)
- self.big_plot_index = 1 # to start with (gets incremented later)
-
- def draw_to_big_plot(self, nodes, edges, mapping_G_to_H):
- plt.subplot(self.big_plot_row_count,
- self.big_plot_row_count, self.big_plot_index)
- self.draw_chimera_graph(1, 1, 4)
- self._draw(nodes, edges, mapping_G_to_H)
- plt.draw()
- self.big_plot_index += 1
-
- def save_big_plot(self, filename):
- plt.savefig(f'./{filename}.svg')
+ def draw_whole_embedding_step(self, nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H, title=''):
+ self.init_figure()
+ self.fig.suptitle(title, fontsize=16)
+ self.draw_chimera_and_embedding(nodes, edges, mapping_G_to_H)
+ self.total_steps += 1
+
+ def save_and_clear(self, path):
+ self.fig.set_size_inches(self.m*3, self.n*3)
+ self.fig.savefig(path, bbox_inches='tight')
+ plt.close(self.fig)
diff --git a/python/src/drawing/node_colors.py b/python/src/drawing/node_colors.py
new file mode 100644
index 0000000..8db660f
--- /dev/null
+++ b/python/src/drawing/node_colors.py
@@ -0,0 +1,23 @@
+supernode_colors = [
+ '#FF4A6D', '#2EB4FF', '#FF8C36', '#2BD8B7', '#AE1CFF',
+ '#2BC2D6', '#DBDE5D', '#11F0EB', '#7D2EFF', '#2B76EF',
+ '#E0165C', '#3CDE73', '#F23827', '#F29E38', '#D33EDB',
+ '#0EA54E'
+]
+
+remember_colors = dict()
+i = 0
+
+
+def get_supernode_color(node_H: int):
+ global i
+
+ if node_H in remember_colors:
+ return remember_colors[node_H]
+
+ # Choose color and remember it
+ color = supernode_colors[i % len(supernode_colors)]
+ remember_colors[node_H] = color
+ i += 1
+
+ return color
diff --git a/python/src/embedding/articulation_point.py b/python/src/embedding/articulation_point.py
new file mode 100644
index 0000000..735abeb
--- /dev/null
+++ b/python/src/embedding/articulation_point.py
@@ -0,0 +1,66 @@
+
+from src.embedding.embedding import EmbeddingGraph
+from src.util.util import get_first_from
+
+
+class ArticulationPointCalculator:
+
+ def __init__(self, G: EmbeddingGraph) -> None:
+ self.G = G
+
+ def calc_articulation_points(self, nodes: set[int]) -> set[int]:
+ """Returns the articulation points aka "cut nodes" in the given subgraph"""
+ self.nodes = nodes
+
+ self.time = 0
+ self.discovery_time = {node: -1 for node in nodes}
+ self.min_level = {node: -1 for node in nodes}
+ self.articulation_points = set()
+
+ self.visited = {node: False for node in nodes}
+ self.parent = {node: -1 for node in nodes}
+ self._dfs_articulation_points(get_first_from(nodes))
+
+ return self.articulation_points.copy()
+
+ def _dfs_articulation_points(self, node: int) -> None:
+ self.visited[node] = True
+
+ children_count = 0
+ self.discovery_time[node] = self.time
+ self.time += 1
+ self.min_level[node] = self.time
+
+ # DFS recursion
+ for neighbor in self.G.get_neighbor_nodes(node):
+ # Only consider nodes in subgraph
+ if neighbor not in self.nodes:
+ continue
+
+ if not self.visited[neighbor]:
+ children_count += 1
+ self.parent[neighbor] = node
+ # Recurse
+ self._dfs_articulation_points(neighbor)
+
+ # Check if the subtree rooted with neighbor has a connection to
+ # one of the ancestors of node
+ self.min_level[node] =\
+ min(self.min_level[node], self.min_level[neighbor])
+
+ # Check if articulation point
+ # Node is an articulation point in the following cases
+ if self.parent[node] == -1:
+ # (1) node is root of DFS tree and has two or more children
+ if children_count > 1:
+ self.articulation_points.add(node)
+ else:
+ # (2) If node is not root and discovery time of node is less
+ # or equal than min_level of one of its children
+ if self.discovery_time[node] <= self.min_level[neighbor]:
+ self.articulation_points.add(node)
+
+ elif neighbor != self.parent[node]: # only if there is a "back-edge"
+ # Update min_level of node
+ self.min_level[node] =\
+ min(self.min_level[node], self.discovery_time[neighbor])
diff --git a/python/src/embedding/embedding.py b/python/src/embedding/embedding.py
index b2de2b1..70ae8d7 100644
--- a/python/src/embedding/embedding.py
+++ b/python/src/embedding/embedding.py
@@ -1,121 +1,151 @@
import itertools
+import logging
from copy import deepcopy
-from typing import List
from src.embedding.graph_mapping import GraphMapping
-from src.graphs.chimera_graph import ChimeraGraphLayout, GraphEmbedding
-from src.graphs.undirected_graphs import UndirectedGraphAdjList
+from src.graph.chimera_graph import ChimeraGraphLayout
+from src.graph.embedding_graph import EmbeddingGraph
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.embedding.articulation_point import ArticulationPointCalculator
+
+logger = logging.getLogger('evolution')
-########################### Embedding blueprint ################################
class Embedding():
- def __init__(self, H: UndirectedGraphAdjList):
+ def __init__(self, H: UndirectedGraphAdjList, m, n, t):
+ """Initializes an Embedding.
- # TODO: explain difference (!) - crucial for understanding
+ Args:
+ H (UndirectedGraphAdjList): The minor Graph to embed
+ """
+ # --- Minor H
self.H = H
- self.G_layout = ChimeraGraphLayout()
- self.G_embedding = GraphEmbedding(8)
- self.G_embedding_view = GraphEmbedding(H.nodes_count)
- self.mapping = GraphMapping()
+ # --- Layout Graph
+ # Graph to embed H onto
+ self.G_layout = ChimeraGraphLayout(m, n, t)
+
+ # --- Embedding Graph
+ # Full graph: nodes are labeled according to G
+ self.G_embedding = EmbeddingGraph(self.G_layout.get_size())
+ # View graph: nodes are labeled according to H
+ self.G_embedding_view = EmbeddingGraph(H.nodes_count)
- def get_embedded_nodes(self) -> List:
- return self.G_embedding.get_embedded_nodes()
+ self.mapping = GraphMapping(H.nodes_count)
- def get_reachable_neighbors(self, from_node):
- return self.G_layout.get_neighbor_nodes(from_node)
+ def get_embedded_nodes(self) -> set[int]:
+ """Returns all embedded nodes.
+
+ Returns:
+ set[int]: The embedded nodes.
+ """
+ embedded_nodes = self.G_embedding.get_embedded_nodes()
+ if not embedded_nodes:
+ raise Exception('No nodes embedded yet')
+ return embedded_nodes
- def get_free_neighbors(self, from_node) -> List:
- neighbors = self.G_layout.get_neighbor_nodes(from_node)
+ def get_reachable_neighbors(self, source):
+ return self.G_layout.get_neighbor_nodes(source)
+
+ def get_free_neighbors(self, source) -> set[int]:
+ neighbors = self.G_layout.get_neighbor_nodes(source)
neighbors_used = self.G_embedding.get_embedded_nodes()
- neighbors_free = [neighbor for neighbor in neighbors
- if neighbor not in neighbors_used]
+ neighbors_free = {neighbor for neighbor in neighbors
+ if neighbor not in neighbors_used}
if not neighbors_free:
- raise NoFreeNeighborNodes(from_node)
+ raise NoFreeNeighborNodes(source)
return neighbors_free
- def get_connected_neighbors(self, from_node) -> List:
- return self.G_embedding.get_neighbor_nodes(from_node)
+ def get_embedded_neighbors(self, source) -> set[int]:
+ return self.G_embedding.get_neighbor_nodes(source)
- def embed_edge(self, node_from, node_to) -> None:
- self.G_embedding.embed_edge(node_from, node_to)
- node_from_H = self.mapping.add_mapping_new_node_H(node_from)
- node_to_H = self.mapping.add_mapping_new_node_H(node_to)
- self.G_embedding_view.embed_edge(node_from_H, node_to_H)
+ def embed_edge(self, node1, node2) -> None:
+ # Embed edge
+ if not self.G_layout.exists_edge(node1, node2):
+ raise NoViableEdge(node1, node2)
+ self.G_embedding.embed_edge(node1, node2)
- def remove_edge_inconsistently(self, from_node, to_node):
- self.G_embedding.remove_edge(from_node, to_node)
+ # Adjust view graph
+ supernode1 = self.mapping.get_supernode_create_if_not_available(node1)
+ supernode2 = self.mapping.get_supernode_create_if_not_available(node2)
+ if supernode1 != supernode2: # avoid unnecessary selfloops
+ self.G_embedding_view.embed_edge(supernode1, supernode2)
- def add_chain_to_used_nodes(self, from_node, to_node, to_node_new=None):
- """
- Adds a new chain. Does NOT check if this chain is even possible in the
- graph at the moment. TODO: "insource" the check to this class
+ # def embed_edge_without_mapping(self, node1, node2) -> None:
+ # # TODO: add warning on how to use this as this will leave inconsistent states
+ # # if not called correctly
+ # if not self.G_layout.exists_edge(node1, node2):
+ # raise NoViableEdge(node1, node2)
+ # self.G_embedding.embed_edge(node1, node2)
+
+ def embed_edge_with_mapping(self, source_H, source_G, target_H, target_G) -> None:
+ # TODO: add warning that this will overwrite the mapping (!)
+ # not extend it
+ self.G_embedding.embed_edge(source_G, target_G)
+ self.mapping.set_mapping(source_H, source_G)
+ self.mapping.set_mapping(target_H, target_G)
+ self.G_embedding_view.embed_edge(source_H, target_H)
+
+ def remove_edge_inconsistently(self, source, target):
+ self.G_embedding.remove_edge(source, target)
+
+ def exists_edge(self, source, target):
+ return self.G_layout.exists_edge(source, target)
+
+ def get_supernode(self, node_G) -> int:
+ return self.mapping.get_node_H(node_G)
+
+ def get_nodes_in_supernode(self, node_H) -> set[int]:
+ return self.mapping.get_nodes_G(node_H)
+
+ def get_nodes_in_supernode_of(self, node_G) -> set[int]:
+ """Returns the nodes in the supernode that ``node_G`` is in.
+
+ Note that ``node_G`` will be included in the resulting set.
"""
- # --- Adjust mapping
- # mapping for from_node stays the same
- from_node_H = self.mapping.get_node_H(node_G=from_node)
- # mapping for to_node is adjusted so that from_node_H maps to from_node AND to_node
- to_node_H = self.mapping.get_node_H(node_G=to_node)
-
- self.mapping.remove_mapping(to_node_H, to_node)
- self.mapping.extend_mapping(from_node_H, to_node)
- self.mapping.extend_mapping(to_node_H, to_node_new)
-
- # --- Adjust embedding
- # Delete all edges from node_to and add respective edges from node_to_new
- to_node_connected_neighbors = self.get_connected_neighbors(to_node)
- self.G_embedding.delete_all_edges_from_node(to_node)
- for prev_connected_neighbor in to_node_connected_neighbors:
- # Avoid edge from node to itself
- if prev_connected_neighbor in [from_node, to_node_new]:
- continue
-
- # to_node_new might be a chain itself
- nodes_in_chain = self.G_embedding.get_nodes_in_same_chain(
- to_node_new)
- embedded = False
- for node_in_chain in nodes_in_chain:
- if self.G_layout.exists_edge(prev_connected_neighbor, node_in_chain):
- self.G_embedding.embed_edge(
- prev_connected_neighbor, node_in_chain
- )
- embedded = True
- break
- if not embedded:
- raise RuntimeError('Error adding a chain to used nodes')
-
- # --- Chain
- self.G_embedding.add_chain(from_node, to_node)
- # Add missing edge node_to---node_to_new
- self.G_embedding.embed_edge(to_node, to_node_new)
-
- # TODO: adjust embedding for self.G_embedding_small_view (???)
-
- def extend_one_node_to_chain(self, frm, to, extend_G):
- """Extends one node to a chain.
-
- Note that en edge from replace_G to frm must be viable. TODO: add a check
+ supernode = self.get_supernode(node_G)
+ return self.get_nodes_in_supernode(supernode)
+
+ def construct_supernode(self, source: int, target: int) -> None:
+ # Embed edge
+ self.G_embedding.embed_edge(source, target)
+
+ # Remove target from previous chain
+ self.try_remove_from_supernode(target)
+
+ # Add to new chain
+ source_supernode = self.mapping.get_supernode_create_if_not_available(source)
+ self.mapping.extend_mapping(source_supernode, target)
+
+ def try_remove_from_supernode(self, node: int):
+ """Removes node from its supernode, leaving us with an inconsistent state.
+
+ If ``node`` was in no supernode, we silently do nothing.
"""
- extend_H = self.mapping.get_node_H(node_G=extend_G)
- self.mapping.extend_mapping(extend_H, frm)
- self.mapping.extend_mapping(extend_H, to)
- chain = self.G_embedding.add_chain(frm, to)
- # avoid inconsistent state
- self.G_embedding.embed_edge(extend_G, frm, chain=chain)
+ try:
+ supernode = self.get_supernode(node)
+ self.mapping.remove_mapping(supernode, node)
+ except KeyError:
+ pass
def is_valid_embedding(self) -> bool:
- for frm in self.H._get_nodes():
- expected_tos = self.H._get_neighbor_nodes(frm)
- actual_tos = self.G_embedding_view.get_neighbor_nodes(frm)
- if actual_tos != expected_tos:
+ for source in self.H.get_nodes():
+ expected_targets = self.H.get_neighbor_nodes(source)
+ actual_targets = self.G_embedding_view.get_neighbor_nodes(source)
+ if actual_targets != expected_targets:
return False
return True
def get_playground(self):
return deepcopy(self)
- def get_embedding(self):
- return self.G_embedding.get_embedding()
+ def get_embedding(self, G_to_H_mapping=True):
+ nodes, edges = self.G_embedding.get_embedding()
+ if G_to_H_mapping:
+ mapping = self.get_mapping_G_to_H()
+ else:
+ mapping = self.get_mapping_H_to_G()
+ return nodes, edges, mapping
def get_mapping_H_to_G(self):
return self.mapping.get_mapping_H_to_G()
@@ -123,45 +153,213 @@ def get_mapping_H_to_G(self):
def get_mapping_G_to_H(self):
return self.mapping.get_mapping_G_to_H()
- def try_to_add_missing_edges(self) -> int:
+ def get_nodes_G(self, node_H: int) -> set[int]:
+ return self.mapping.get_nodes_G(node_H)
+
+ def get_nodes_H(self) -> set[int]:
+ return self.H.get_nodes()
+
+ def get_supernode_degree_percentages(self) -> dict[int, float]:
+ """Returns a dictionary of percentages for each supernode indicating
+ how many edges between supernodes are currently embedded in G compared
+ to how many should be as specified in the input graph H."""
+ degree_percentages = {}
+ for source_H in self.H.get_nodes():
+ expected_degree = len(self.H.get_neighbor_nodes(source_H))
+ actual_degree = len(self.G_embedding_view.get_neighbor_nodes(source_H))
+ degree_percentages[source_H] = min(1.0, actual_degree / expected_degree)
+ return degree_percentages
+
+ def _get_supernode_sizes(self) -> dict[int, int]:
+ supernode_sizes = {}
+ for source_H in self.H.get_nodes():
+ supernode_nodes = self.get_nodes_in_supernode(source_H)
+ supernode_sizes[source_H] = len(supernode_nodes)
+ return supernode_sizes
+
+ def get_sorted_supernodes_by_size(self) -> list[int]:
+ """Returns a list of sorted supernode keys according to their size
+ (how many nodes in the hardware graph they map onto).
"""
- Tries to add missing edges if possible.
+ supernode_sizes = self._get_supernode_sizes()
+ # sort according to value (supernode size)
+ sorted_entries = sorted(supernode_sizes.items(), key=lambda item: item[1])
+ return [entry[0] for entry in sorted_entries]
+
+ def try_embed_missing_edges(self) -> int:
+ """Tries to embed missing edges if possible.
- Returns
- -------
- How many missing edges were successfully added.
+ Returns:
+ int: How many missing edges were successfully added.
"""
- missing_edges_added = 0
-
- for frm in self.H._get_nodes():
- expected_tos = self.H._get_neighbor_nodes(frm)
- actual_tos = self.G_embedding_view.get_neighbor_nodes(frm)
- # actual_tos = [self.G_embedding_view.get_neighbor_nodes(frm)
- # for frm in self.mapping.get_node_G(node_H=frm)]
- # actual_tos = list(itertools.chain(*actual_tos)) # flatten
-
- for to in expected_tos:
- if to not in actual_tos:
- # print(f'missing edge from H: {frm}-{to}')
- # Can we add this edge with the current embedding?
- possible_edges = list(itertools.product(
- self.mapping.get_node_G(node_H=frm), self.mapping.get_node_G(node_H=to)))
- # product since we are dealing with possible chains
+ missing_edges_added = set()
+
+ for source_H in self.H.get_nodes():
+ expected_targets = self.H.get_neighbor_nodes(source_H)
+ actual_targets = self.G_embedding_view.get_neighbor_nodes(source_H)
+ for target_H in expected_targets:
+ if target_H not in actual_targets:
+ # All possible combination (accounting for supernodes)
+ source_supernode_nodes = self.get_nodes_in_supernode(source_H)
+ target_supernode_nodes = self.get_nodes_in_supernode(target_H)
+ possible_edges = itertools.product(
+ source_supernode_nodes, target_supernode_nodes)
+
+ # Can we add missing edge with the current embedding?
for possible_edge in possible_edges:
- if self.G_layout.exists_edge(possible_edge[0], possible_edge[1]):
+ try:
self.embed_edge(possible_edge[0], possible_edge[1])
- print(f'added missing edge from H: {frm}-{to}')
- missing_edges_added += 1
+ # logger.info(
+ # f'➕ Added missing edge in H: {source_H}-{target_H}')
+ missing_edges_added.add((source_H, target_H))
break # successfully added missing edge
+ except:
+ pass # it's ok if we found no possible edge
+
+ # Log
+ logger.info('Try to add missing edges')
+ for edge in missing_edges_added:
+ logger.info(f'➕ Added missing edge in H: {edge[0]}-{edge[1]}')
+
+ return len(missing_edges_added)
+
+ def remove_redundancy(self) -> None:
+ self.remove_redundant_supernode_nodes()
+ self.remove_unnecessary_edges_between_supernodes()
+
+ def remove_unnecessary_edges_between_supernodes(self) -> None:
+ """Tries to remove unnecessary edges, e.g. multiple edges between
+ two supernodes.
+ """
+ logger.info('Remove unnecessary edges between supernodes')
+ # For every supernode (chain)
+ for supernode in self.H.get_nodes():
+ considered_supernodes = []
+
+ # For every node in supernode (chain)
+ for node in self.get_nodes_in_supernode(supernode):
+
+ # Go through every edge to a neighbor
+ # that is in ANOTHER supernode
+ for neighbor in self.get_embedded_neighbors(node):
+ neighbor_supernode = self.get_supernode(neighbor)
+
+ # Do not consider edges inside of supernodes
+ if supernode == neighbor_supernode:
+ continue
+
+ # Only keep the edge if we didn't have any connection
+ # to neighbor's supernode yet
+ if neighbor_supernode not in considered_supernodes:
+ considered_supernodes.append(neighbor_supernode)
+ else:
+ self.G_embedding.remove_edge(node, neighbor)
+ # No need adjust G_embedding_view as
+ # this must be preserved by this method
+
+ def remove_redundant_supernode_nodes(self):
+ logger.info('Removing redundant supernode nodes')
+ for supernode in self.H.get_nodes():
+ self.remove_redundant_nodes_in_supernode(supernode)
+
+ def remove_redundant_nodes_in_supernode(self, supernode) -> None:
+ supernode_nodes = self.get_nodes_in_supernode(supernode)
+
+ if len(supernode_nodes) == 1:
+ return
+
+ removed_nodes = set()
+ while True:
+ removed_in_this_iteration = False
+
+ # Calculate articulation points
+ # We need to recalculate them every time a node was removed
+ # since the articulation points might change in this case
+ articulation_points = ArticulationPointCalculator(self.G_embedding)\
+ .calc_articulation_points(supernode_nodes - removed_nodes)
+ logger.info(f'supernode {supernode} (nodes: {supernode_nodes}) '
+ + f'has articulation points: {articulation_points}')
+
+ # Try to remove ONE node in the supernode
+ for node_to_remove in supernode_nodes:
+ if node_to_remove in removed_nodes:
+ continue
+
+ # Don't remove articulation points (aka "cut nodes")
+ if node_to_remove in articulation_points:
+ continue
+
+ # Can we reach all previous neighbors of supernode?
+ node_to_remove_neighbors = self.get_embedded_neighbors(node_to_remove)
+ if node_to_remove_neighbors:
+ rest_nodes_reachable = [self.get_embedded_neighbors(node)
+ for node in supernode_nodes
+ if node != node_to_remove]
+ rest_nodes_reachable = itertools.chain(*rest_nodes_reachable)
+
+ if not all([neighbor in rest_nodes_reachable
+ for neighbor in node_to_remove_neighbors
+ # chain connectivity already ensured
+ if neighbor not in supernode_nodes]):
+ continue
+
+ # We can now safely remove the node
+ self.remove_node(node_to_remove)
+ removed_in_this_iteration = True
+ removed_nodes.add(node_to_remove)
+ logger.info(f'✂ Removed node: {node_to_remove}')
+
+ # Leave at least one node left of every supernode
+ if len(removed_nodes) == (len(supernode_nodes) - 1):
+ return
+
+ break
+
+ if not removed_in_this_iteration:
+ return
+
+ def remove_node(self, node: int) -> None:
+ # Embedding
+ self.G_embedding.remove_node(node)
+
+ # Mapping
+ supernode = self.get_supernode(node)
+ self.mapping.remove_mapping(supernode, node)
+
+ def check_supernode_connectiveness(self, supernode: int) -> bool:
+ """Checks that no supernodes are split up into multiple groups
+ by the mutation. All nodes in a supernode must have an edge to at least
+ one other supernode.
+ """
+ supernode_nodes = self.get_nodes_in_supernode(supernode)
+ for node in supernode_nodes:
+ embedded_neighbors = self.get_embedded_neighbors(node)
+
+ reached = False
+ for neighbor in embedded_neighbors:
+ neighbor_supernode = self.get_supernode(neighbor)
+ if neighbor_supernode == supernode:
+ reached = True
- return missing_edges_added
+ if not reached:
+ return False
+
+ return True
############################### Exceptions #####################################
class NoFreeNeighborNodes(Exception):
- def __init__(self, from_node):
- self.from_node = from_node
+ def __init__(self, source):
+ self.source = source
+
+ def __str__(self):
+ return f'Node {self.source} has no free neighbors'
+
+
+class NoViableEdge(Exception):
+ def __init__(self, node1, node2):
+ self.edge = (node1, node2)
def __str__(self):
- return f'NoFreeNeighborNodes from node: {self.from_node}'
+ return f'Not a valid edge: {self.edge[0]}-{self.edge[1]}'
diff --git a/python/src/embedding/graph_mapping.py b/python/src/embedding/graph_mapping.py
index edaa9d7..1e47597 100644
--- a/python/src/embedding/graph_mapping.py
+++ b/python/src/embedding/graph_mapping.py
@@ -1,26 +1,32 @@
+from typing import Optional
+
+
class GraphMapping():
"""
Invertable unique dict using sets as values to encode the mapping between
- the small view of a graph and the big view.
+ nodes in the input graph H to embed into the hardware graph G.
"""
- def __init__(self):
+ def __init__(self, size_H: int):
self.H_to_G = dict() # values are ints
self.G_to_H = dict() # values are sets
+ self.max_supernodes_count = size_H
- def get_node_G(self, node_H):
- # we explicitly do NOT handle KeyErrors here as they should never happen
- return self.H_to_G[node_H]
+ def get_nodes_G(self, node_H: int) -> set[int]:
+ # Note that we do not handle KeyErrors here as they should never occur
+ # Might want to use method: get_supernode_create_if_not_available()
+ return self.H_to_G[node_H].copy()
- def get_node_H(self, node_G):
- # we explicitly do NOT handle KeyErrors here as they should never happen
+ def get_node_H(self, node_G: int) -> int:
+ # Note that we do not handle KeyErrors here as they should never occur
return self.G_to_H[node_G]
- def __set_mapping(self, node_H: int, node_G: int):
+ def set_mapping(self, node_H: int, node_G: int):
self.H_to_G[node_H] = set([node_G])
self.G_to_H[node_G] = node_H
def extend_mapping(self, node_H: int, node_G: int):
+ """Places ``node_G`` into the super node representing ``node_H``."""
try:
self.H_to_G[node_H].add(node_G)
except KeyError:
@@ -28,22 +34,32 @@ def extend_mapping(self, node_H: int, node_G: int):
self.G_to_H[node_G] = node_H
def remove_mapping(self, node_H: int, node_G: int):
+ """Removes ``node_G`` from the super node represents ``node_H``."""
self.H_to_G[node_H].remove(node_G)
del self.G_to_H[node_G]
- def add_mapping_new_node_H(self, node_G: int):
- # Check if there exists already a mapping
+ def get_supernode_create_if_not_available(self, node_G: int) -> int:
+ """Returns the supernode for ``node_G``.
+
+ If there is no supernode of ``node_G``, create a new supernode and return it.
+ """
try:
- node_H = self.G_to_H[node_G]
- return node_H
+ supernode = self.G_to_H[node_G]
except KeyError:
- # Make new mapping to new node
- node_H = len(self.H_to_G.keys())
- self.__set_mapping(node_H, node_G)
- return node_H
+ supernode = self._get_new_supernode()
+ self.set_mapping(supernode, node_G)
+
+ return supernode
+
+ def _get_new_supernode(self) -> int:
+ supernode = len(self.H_to_G.keys())
+ if supernode >= self.max_supernodes_count:
+ raise KeyError(f'Maximum of possible embeddings reached: '
+ f'{self.max_supernodes_count}')
+ return supernode
def get_mapping_H_to_G(self):
- return self.H_to_G
-
+ return self.H_to_G.copy()
+
def get_mapping_G_to_H(self):
- return self.G_to_H
+ return self.G_to_H.copy()
diff --git a/python/src/graph/__init__.py b/python/src/graph/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/python/src/graph/chimera_graph.py b/python/src/graph/chimera_graph.py
new file mode 100644
index 0000000..d2c3a8a
--- /dev/null
+++ b/python/src/graph/chimera_graph.py
@@ -0,0 +1,96 @@
+import dwave_networkx as dnx
+from src.graph.undirected_graph import UndirectedGraphAdjList
+
+
+class ChimeraGraphLayout(UndirectedGraphAdjList):
+
+ def __init__(self, m: int, n: int, t=4):
+ """Creates a Chimera lattice of size (m, n, t).
+
+ Args:
+ m (int): Number of rows in the Chimera lattice.
+ n (int, optional, default m): Number of columns in the Chimera lattice.
+ t (int, optional, default 4): Size of the shore within each Chimera tile.
+
+ Returns:
+ G : NetworkX Graph
+ An (m, n, t) Chimera lattice. Nodes are labeled by integers.
+
+ A Chimera lattice is an m-by-n grid of Chimera tiles. Each Chimera
+ tile is itself a bipartite graph with shores of size t. The
+ connection in a Chimera lattice can be expressed using a node-indexing
+ notation (i,j,u,k) for each node.
+
+ * (i,j) indexes the (row, column) of the Chimera tile. i must be
+ between 0 and m-1, inclusive, and j must be between 0 and
+ n-1, inclusive.
+ * u=0 indicates the left-hand nodes in the tile, and u=1 indicates
+ the right-hand nodes.
+ * k=0,1,...,t-1 indexes nodes within either the left- or
+ right-hand shores of a tile.
+
+ In this notation, two nodes (i, j, u, k) and (i', j', u', k') are
+ neighbors if and only if:
+
+ (i = i' AND j = j' AND u != u') OR
+ (i = i' +/- 1 AND j = j' AND u = 0 AND u' = 0 AND k = k') OR
+ (i = i' AND j = j' +/- 1 AND u = 1 AND u' = 1 AND k = k')
+
+ The first of the three terms of the disjunction gives the
+ bipartite connections within the tile. The second and third terms
+ give the vertical and horizontal connections between blocks
+ respectively.
+
+ (Partially copied from the official dwave_networkx documentation.)
+ """
+
+ # --- Nodes
+ nodes_count = m * n * 2 * t
+ self.nodes_count = nodes_count
+ super().__init__(nodes_count)
+
+ # --- Edges
+ G = dnx.chimera_graph(m, n, t)
+ for e in G.edges:
+ self.set_edge(e[0], e[1])
+
+ def get_size(self) -> int:
+ return self.nodes_count
+
+ # def __init__(self, grid_width=1):
+ # # --- Nodes
+ # # One chimera cell has 8 nodes
+ # nodes_count = 8 * grid_width**2
+ # super().__init__(nodes_count)
+
+ # # --- Edges
+ # # Start from top-left corner to top-right
+ # # then go bottom
+ # cell_start_offset = 0
+
+ # for i in range(grid_width):
+ # for j in range(grid_width):
+
+ # # --- One Chimera cell
+ # for chimera_i in range(0, 4):
+ # for chimera_j in range(4, 8):
+ # self.set_edge(chimera_i + cell_start_offset,
+ # chimera_j + cell_start_offset)
+
+ # # --- Edges to other cells
+
+ # # 0,1,2,3 to bottom cell
+ # # Check that we are not one of most bottom cells
+ # if i != grid_width - 1:
+ # for chimera_i in range(0, 4):
+ # self.set_edge(chimera_i + grid_width,
+ # chimera_i + grid_width + (grid_width*8))
+
+ # # 4,5,6,7 to right-hand cell
+ # # Check that we are not one of most right-hand cells
+ # if j != grid_width - 1:
+ # for chimera_j in range(4, 8):
+ # self.set_edge(chimera_j + cell_start_offset,
+ # chimera_j + cell_start_offset + 8)
+
+ # cell_start_offset += 8
diff --git a/python/src/graph/embedding_graph.py b/python/src/graph/embedding_graph.py
new file mode 100644
index 0000000..0d5ea52
--- /dev/null
+++ b/python/src/graph/embedding_graph.py
@@ -0,0 +1,80 @@
+from src.graph.undirected_graph import UndirectedGraphAdjList
+
+
+class EmbeddingGraph(UndirectedGraphAdjList):
+ """A Graph to **form** an embedding (using an adjacency list).
+
+ This Graph is supposed to **converge into a valid minor** of another graph
+ by using the methods it provides, e.g. to embed edges, form chains etc.
+
+ Hint:
+ Pay attention whether you use methods which are directly defined here
+ or in the parent class
+ :py:class:`src.graph.undirected_graph.UndirectedGraphAdjList`.
+ Methods defined over there may not be convenient as the current class
+ tries to hide implementation details, e.g. chains being encoded as
+ edge costs. It is recommend to just stick to the methods defined here
+ (in the subclass).
+
+ Warning:
+ This class does not implement any checks for chains, so it is possible
+ to assign a node to multiple chains.
+ """
+
+ def __init__(self, nodes_count):
+ self._chain_last = 0
+ super().__init__(nodes_count)
+
+ ############################### Edges ######################################
+
+ def embed_edge(self, frm: int, to: int) -> None:
+ """Embeds an edge (and optionally assigns a chain).
+
+ Args:
+ frm (int): One node of the edge.
+ to (int): The other node of the edge.
+ chain (int, optional): The chain to assign to the new embedded edge. \
+ The default value `0` means: no chain, just a "normal" edge.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` or ``to`` \
+ does not exist in the Graph.
+ """
+ super().set_edge(frm, to, cost=0)
+
+ def get_embedded_edges(self) -> set[tuple[int, int, int]]:
+ """Returns all embedded edges.
+
+ Returns:
+ set[tuple[int, int, int]]: A set of entries (frm, to, cost) \
+ describing all embedded edges of this Graph with their \
+ respective costs.
+ """
+ return super().get_edges()
+
+ ################################# Nodes ####################################
+
+ def get_embedded_nodes(self) -> set[int]:
+ """Returns all embedded nodes.
+
+ Returns:
+ set[int]: The embedded nodes.
+ """
+ nodes = super().get_nodes()
+ nodes = {node for node in nodes if self.get_neighbor_nodes(node)}
+ return nodes
+
+ ############################### Embedding ##################################
+
+ def get_embedding(self) -> tuple[set[int], set[tuple[int, int, int]]]:
+ """Returns the current embedding.
+
+ Returns:
+ tuple[list[int], list[tuple[int, int, int]]]: \
+ A tuple of nodes and edges. `nodes` is a list of integers, \
+ while `edges` is a list of tuples (frm, to, chain) describing \
+ the edges (frm node, to node, chain)
+ """
+ nodes = self.get_embedded_nodes()
+ edges = self.get_embedded_edges()
+ return nodes, edges
diff --git a/python/src/graph/test_graph.py b/python/src/graph/test_graph.py
new file mode 100644
index 0000000..7200377
--- /dev/null
+++ b/python/src/graph/test_graph.py
@@ -0,0 +1,66 @@
+import networkx as nx
+from src.graph.undirected_graph import UndirectedGraphAdjList
+
+
+class TestGraph():
+
+ @staticmethod
+ def house() -> UndirectedGraphAdjList:
+ H = UndirectedGraphAdjList(5)
+ H.set_edge(0, 1)
+ H.set_edge(0, 4)
+ H.set_edge(1, 2)
+ H.set_edge(1, 3)
+ H.set_edge(2, 3)
+ H.set_edge(3, 4)
+ return H
+
+ @staticmethod
+ def i_letter() -> UndirectedGraphAdjList:
+ H = UndirectedGraphAdjList(6)
+ H.set_edge(0, 3)
+ H.set_edge(3, 2)
+ H.set_edge(3, 5)
+ H.set_edge(1, 2)
+ H.set_edge(2, 4)
+ return H
+
+ @staticmethod
+ def k(n: int) -> UndirectedGraphAdjList:
+ G = nx.complete_graph(n)
+ H = UndirectedGraphAdjList(n)
+ for e in G.edges:
+ H.set_edge(e[0], e[1])
+ return H
+
+ @staticmethod
+ def pyramid() -> UndirectedGraphAdjList:
+ H = UndirectedGraphAdjList(5)
+ H.set_edge(0, 1)
+ H.set_edge(0, 2)
+ H.set_edge(0, 3)
+ H.set_edge(0, 4)
+ H.set_edge(1, 2)
+ H.set_edge(2, 3)
+ H.set_edge(3, 4)
+ return H
+
+ @staticmethod
+ def tree_like() -> UndirectedGraphAdjList:
+ H = UndirectedGraphAdjList(6)
+ H.set_edge(0, 1)
+ H.set_edge(0, 2)
+ H.set_edge(0, 3)
+ H.set_edge(1, 4)
+ H.set_edge(1, 5)
+ H.set_edge(2, 5) # comment this line out to get a tree
+ return H
+
+ @staticmethod
+ def crossed_house() -> UndirectedGraphAdjList:
+ # In Germany known as "Haus vom Nikolaus"
+ H = TestGraph.k(4)
+ new_node = H.add_node()
+ H.set_edge(1, new_node)
+ H.set_edge(2, new_node)
+ return H
diff --git a/python/src/graph/undirected_graph.py b/python/src/graph/undirected_graph.py
new file mode 100644
index 0000000..e9d5818
--- /dev/null
+++ b/python/src/graph/undirected_graph.py
@@ -0,0 +1,280 @@
+class UndirectedGraphAdjList:
+ """
+ Undirected Graph using an adjacency list.
+ """
+
+ def __init__(self, nodes_count: int):
+ """Initializes a new Graph.
+
+ Args:
+ nodes_count (int): The number of nodes this Graph \
+ has initially.
+ """
+ self._adj_list: dict[int, AdjListEntryWithCosts] = dict()
+ self.current_index = -1
+ self.nodes_count = 0 # gets incremented in for loop
+ for _ in range(nodes_count):
+ self.add_node()
+
+ def _validate_index(self, index: int):
+ """Checks if the given index is valid for the current Graph."""
+ try:
+ self._adj_list[index]
+ except KeyError:
+ raise GraphNodeIndexError(index)
+
+ ############################### Edges ######################################
+
+ def get_edges(self) -> set[tuple[int, int, int]]:
+ """Returns all edges of this Graph.
+
+ Returns:
+ set[tuple[int, int, int]]: A set of entries (frm, to, cost) \
+ describing all edges of this Graph with their respective costs.
+ """
+ edges = set()
+ for frm in self._adj_list.keys():
+ for (to, cost) in self._adj_list[frm].get_neighbors_with_costs():
+ # frm, to = to, frm
+ # would be fatal here inside the loop (!)
+ if frm < to:
+ edges.add((frm, to, cost))
+ else:
+ edges.add((to, frm, cost))
+ return set(edges)
+
+ def exists_edge(self, frm: int, to: int) -> bool:
+ """Checks if an edge between two nodes exists.
+
+ Args:
+ frm (int): One node of the edge.
+ to (int): The other node of the edge.
+
+ Returns:
+ bool: True if the edge exists.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` or ``to`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(frm)
+ self._validate_index(to)
+ return to in self.get_neighbor_nodes(frm)
+
+ def set_edge(self, frm: int, to: int, cost=0) -> None:
+ """Sets an edge between nodes ``frm`` and ``to`` and assigns
+ the given ``cost``.
+
+ Warning:
+ This may override an existing edge with new costs.
+
+ Args:
+ frm (int): One node of the edge.
+ to (int): The other node of the edge.
+ cost (int): The costs for the edge
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` or ``to`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(frm)
+ self._validate_index(to)
+
+ self._adj_list[frm].set_edge_to(to, cost)
+ self._adj_list[to].set_edge_to(frm, cost) # undirected graph
+
+ def remove_edge(self, frm: int, to: int) -> None:
+ """Removes the edge (if present) between nodes ``frm`` and ``to``.
+
+ Args:
+ frm (int): One node of the edge.
+ to (int): The other node of the edge.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` or ``to`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(frm)
+ self._validate_index(to)
+
+ self._adj_list[frm].remove_edge_to(to)
+ self._adj_list[to].remove_edge_to(frm) # undirected graph
+
+ def remove_all_edges_from_node(self, frm: int) -> None:
+ """Removes all edges connected to the given node.
+
+ Args:
+ frm (int): node from which all edges should be removed.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(frm)
+
+ tos = self._adj_list[frm].get_neighbors()
+ if not tos:
+ return # nothing to delete
+
+ for to in tos:
+ # Delete outgoing edges (by resetting)
+ self._adj_list[frm].remove_edge_to(to)
+
+ # Delete incoming edges
+ self._adj_list[to].remove_edge_to(frm)
+
+ ################################# Nodes ####################################
+
+ def get_nodes(self) -> set[int]:
+ """Returns all nodes of this Graph.
+
+ Returns:
+ set[int]: All nodes of this Graph.
+ """
+ return set(self._adj_list.keys())
+
+ def add_node(self) -> int:
+ """Adds a new node to this Graph.
+
+ Returns:
+ int: The new node number.
+ """
+ self.nodes_count += 1
+ self._adj_list[self.nodes_count-1] = AdjListEntryWithCosts()
+ return self.nodes_count-1
+
+ def remove_node(self, node: int) -> None:
+ self.remove_all_edges_from_node(node)
+
+ # We don't delete the key completely as we use the following encoding:
+ # Nodes are only embedded nodes later if they have neighbors
+ # del self._adj_list[node]
+
+ def get_neighbor_nodes(self, source: int) -> set[int]:
+ """Returns all neighboring nodes.
+
+ Neighboring nodes are nodes that are connected via an edge to this node.
+
+ Args:
+ source (int): Node from which the neighboring nodes should be retrieved.
+
+ Return:
+ set[int]: Set of integers describing the neighboring nodes.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``source`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(source)
+ return self._adj_list[source].get_neighbors()
+
+ def get_neighbor_nodes_with_costs(self, frm: int) -> list[tuple[int, int]]:
+ """Returns all neighboring nodes with costs.
+
+ Neighboring nodes are nodes that are connected via an edge to this node.
+
+ Args:
+ frm (int): Node from which the neighboring nodes \
+ should be retrieved.
+
+ Return:
+ list[tuple[int, int]]: List of tuples (to, cost) \
+ describing edges with costs.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` \
+ does not exist in the Graph.
+ """
+ self._validate_index(frm)
+ return self._adj_list[frm].get_neighbors_with_costs()
+
+ def has_neighbor_nodes(self, frm: int) -> bool:
+ """Checks if the given node has neighboring nodes.
+
+ Neighboring nodes are nodes that are connected via an edge to this node.
+
+ Args:
+ frm (int): Node from which the neighboring nodes should be retrieved.
+
+ Returns:
+ bool: True if the given node has neighboring nodes.
+
+ Raises:
+ GraphNodeIndexError: If the given node ``frm`` \
+ does not exist in the Graph.
+ """
+ return len(self.get_neighbor_nodes(frm)) > 0
+
+
+class GraphNodeIndexError(Exception):
+ """Error that occurs when accessing a node that does not exist in the Graph.
+
+ Args:
+ index (int): Invalid node (represented as integer index in the Graph).
+ """
+
+ def __init__(self, index: int):
+ message = f'Node {index} does not exist in the graph'
+ super().__init__(message)
+
+
+class AdjListEntryWithCosts():
+ """One entry of an adjacency list.
+
+ Describes edges to other nodes and assigns costs to these edges.
+
+ Warning:
+ This AdjacencyList does *not* check for invalid indexing.
+ Expect KeyErrors to arise if the caller does not handle indexing correctly.
+
+ Note:
+ It is guaranteed that an edge from node u to node v cannot exist \
+ multiple times with different costs.
+ """
+
+ def __init__(self):
+ self._to_nodes = set()
+ self._costs = dict()
+
+ ############################### Edges ######################################
+
+ def set_edge_to(self, to: int, cost: int) -> None:
+ """Sets an undirected edge with cost to a node.
+
+ Warning:
+ This may override an existing edge with new costs.
+
+ Args:
+ to (int): Other node to specify the edge.
+ cost (int): Cost for the edge
+ """
+ self._to_nodes.add(to)
+ self._costs[to] = cost # may alter the costs for an existing edge
+
+ def remove_edge_to(self, to: int) -> None:
+ """Removes an edge to a node.
+
+ Args:
+ to (int): Other node to specify the edge that should be removed.
+ """
+ self._to_nodes.remove(to)
+ del self._costs[to]
+
+ ################################# Nodes ####################################
+
+ def get_neighbors(self) -> set[int]:
+ """Returns all neighboring nodes.
+
+ Returns:
+ set[int]: All neighboring nodes (from the current node).
+ """
+ return self._to_nodes.copy()
+
+ def get_neighbors_with_costs(self) -> list[tuple[int, int]]:
+ """Returns all neighboring nodes with costs (from the current node).
+
+ Returns:
+ list[tuple[int, int]]: All neighboring nodes (from the \
+ current node) with costs.
+ """
+ return [(to, self._costs[to]) for to in self._to_nodes]
diff --git a/python/src/graphs/chimera_graph.py b/python/src/graphs/chimera_graph.py
deleted file mode 100644
index 22b22a2..0000000
--- a/python/src/graphs/chimera_graph.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from src.graphs.undirected_graphs import (UndirectedGraphAdjList,
- UndirectedGraphAdjMatrix)
-
-# Chimera graph Graph gird structure (not needed right now)
-# 4
-# x x x x ——4
-# 5 x x x x ——5
-# 0 1 2 3 x x x x ——6
-# 6 x x x x ——7
-# | | | |
-# 7 0 1 2 3
-#
-
-
-class ChimeraGraphLayout(UndirectedGraphAdjList):
- """
- A Chimera graph representation (right now with fixed shore_size of 4
- and a single unit cell TODO).
- """
-
- def __init__(self):
- shore_size = 4 # TODO: init layout of ChimeraGraph dynamically
- vertices_count = shore_size * 2
- super().__init__(vertices_count)
-
- # Define layout of Chimera graphs
- for i in range(0, 4): # TODO: use shore_size here
- for j in range(4, 8):
- self._set_edge(i, j)
-
- def get_neighbor_nodes(self, from_node):
- return super()._get_neighbor_nodes(from_node)
-
- def exists_edge(self, frm, to):
- return to in super()._get_neighbor_nodes(frm)
-
-
-class GraphEmbedding(UndirectedGraphAdjList):
- """
- A Graph Embedding
- """
-
- def __init__(self, nodes_count):
- self._chain_last = 0
- super().__init__(nodes_count)
-
- def get_neighbor_nodes(self, from_node):
- return super()._get_neighbor_nodes(from_node)
-
- def embed_edge(self, frm, to, chain=0):
- # Chain=0 means no chain, just a "normal" edge
- super()._set_edge(frm, to, cost=chain)
-
- def get_nodes_in_same_chain(self, node):
- chain = self._get_node_chain(node)
- if chain == 0:
- return node
- return self._get_chain_nodes(chain)
-
- def _get_node_chain(self, node):
- edges = super()._get_edges_from_node(node)
- if not edges:
- return 0
- else:
- return edges[0][1]
-
- def _get_chain_nodes(self, chain):
- if chain == 0:
- return []
-
- nodes = super()._get_nodes()
- return [node for node in nodes
- if self._get_node_chain(node) == chain]
-
- def remove_edge(self, frm, to):
- super()._remove_edge(frm, to)
-
- def delete_all_edges_from_node(self, frm):
- super()._delete_all_edges_from_node(frm)
-
- def add_chain(self, node1, node2):
- self._chain_last += 1
- self.embed_edge(node1, node2, chain=self._chain_last)
- return self._chain_last
-
- def add_node(self):
- super()._add_node()
-
- def get_embedded_nodes(self):
- nodes = super()._get_nodes()
- # Filter for nodes that have an edge
- nodes = [node for node in nodes if self._adj_list[node].get()]
- return nodes
-
- def get_free_nodes(self):
- nodes = super()._get_nodes()
- # Filter for nodes that don't have an edge
- nodes = [node for node in nodes if not self._has_node_edges(node)]
- return nodes
-
- def get_embedded_edges(self):
- return super()._get_edges()
-
- def get_embedding(self):
- nodes = self.get_embedded_nodes()
- edges = self.get_embedded_edges()
- return nodes, edges
diff --git a/python/src/graphs/undirected_graphs.py b/python/src/graphs/undirected_graphs.py
deleted file mode 100644
index 8d24b82..0000000
--- a/python/src/graphs/undirected_graphs.py
+++ /dev/null
@@ -1,132 +0,0 @@
-class UndirectedGraphAdjMatrix:
- """
- An undirected Graph representation using an adjacency MATRIX with costs.
- The number of graph vertices is fixed after initialization.
-
- - `-1` in the adjacency matrix means: no edge
- - `0` in the adjacency matrix means: edge with cost 0 (default for cost)
- """
-
- def __init__(self, vertices_count):
- self.vertices_count = vertices_count
- self._adj_matrix = [[-1]*vertices_count for x in range(vertices_count)]
-
- def _set_edge(self, frm, to, cost=0):
- self._adj_matrix[frm][to] = cost
- # set vice-versa to preserve symmetric matrix (undirected graph)
- self._adj_matrix[to][frm] = cost
-
- def _get_edge_cost(self, frm, to):
- return self._adj_matrix[frm][to]
-
- def _get_edges(self):
- edges = []
- for i in range(self.vertices_count):
- for j in range(self.vertices_count):
- if (self._adj_matrix[i][j] != -1):
- edges.append((i, j, self._adj_matrix[i][j]))
- return edges
-
- def _get_adj_matrix(self):
- return self._adj_matrix
-
-
-class UndirectedGraphAdjList:
- """
- An undirected Graph representation using an adjacency LIST without costs.
- The number of graph vertices is fixed after initialization.
-
- This class may be primarily used for O(1) search for whether there is
- an edge from vertex u to vertex v.
- """
-
- def __init__(self, nodes_count):
- self.nodes_count = nodes_count
- self._adj_list = dict()
- for i in range(nodes_count):
- self._adj_list[i] = AdjListEntryWithCosts()
-
- def _set_edge(self, frm, to, cost=0):
- try:
- self._adj_list[frm].add(to, cost)
- # set vice-versa to preserve symmetric matrix (undirected graph)
- self._adj_list[to].add(frm, cost)
- except:
- raise IndexError(
- f'Graph only contains {self.nodes_count} vertices')
-
- def _remove_edge(self, frm, to):
- self._adj_list[frm].remove(to)
- self._adj_list[to].remove(frm)
-
- def _delete_all_edges_from_node(self, frm):
- tos = self._adj_list[frm].get_to_nodes()
- if not tos:
- return
-
- # Delete all outgoing edges
- self._adj_list[frm] = AdjListEntryWithCosts()
-
- # Delete specific incoming edges
- for to in tos:
- self._adj_list[to].remove(frm)
-
- def _get_edges_from_node(self, from_node):
- try:
- return self._adj_list[from_node].get()
- except:
- raise IndexError(
- f'Graph only contains {self.nodes_count} vertices')
-
- def _get_neighbor_nodes(self, from_node):
- neighbors = self._get_edges_from_node(from_node)
- # We only need the neighbor nodes, no costs
- neighbors = [neighbor[0] for neighbor in neighbors]
- return neighbors
-
- def _has_node_edges(self, node):
- return len(self._adj_list[node].get()) > 0
-
- def _get_nodes(self):
- return self._adj_list.keys()
-
- def _add_node(self):
- self.nodes_count += 1
- self._adj_list[self.nodes_count-1] = AdjListEntryWithCosts()
-
- def _get_edges(self):
- edges = set()
- for frm in self._adj_list.keys():
- for (to, cost) in self._adj_list[frm].get():
- # frm, to = to, frm
- # would be fatal here inside the loop (!)
- if frm < to:
- edges.add((frm, to, cost))
- else:
- edges.add((to, frm, cost))
- return edges
-
-
-class AdjListEntryWithCosts():
- """
- One entry of an adjacency list. Allows for costs. Makes sure that an edge
- from node u to node v cannot exist multiple times with different costs.
- """
-
- def __init__(self):
- self.to_nodes = set()
- self.costs = dict()
-
- def add(self, to, cost):
- self.to_nodes.add(to)
- self.costs[to] = cost # may alter the costs for an existing edge
-
- def remove(self, to):
- self.to_nodes.remove(to)
- del self.costs[to]
-
- def get_to_nodes(self):
- return self.to_nodes
-
- def get(self):
- return [(to, self.costs[to]) for to in self.to_nodes]
diff --git a/python/src/results/chances.txt b/python/src/results/chances.txt
new file mode 100644
index 0000000..4baab79
--- /dev/null
+++ b/python/src/results/chances.txt
@@ -0,0 +1,2 @@
+[0.5 0. 0. 0. 0. 0.5 0. 0. 0. 0. 0. 0. ]
+[0.06 0.01 0.1 0.07 0. 0.08 0.13 0.16 0.15 0.03 0.12 0.09]
\ No newline at end of file
diff --git a/python/src/results/degree_percentage.py b/python/src/results/degree_percentage.py
new file mode 100644
index 0000000..74d1f12
--- /dev/null
+++ b/python/src/results/degree_percentage.py
@@ -0,0 +1,113 @@
+import csv
+
+import matplotlib.pyplot as plt
+import matplotlib.ticker as ticker
+from src.drawing.node_colors import get_supernode_color
+from src.embedding.embedding import Embedding
+
+# Matplotlib
+# https://stackoverflow.com/a/7389998
+# https://stackoverflow.com/a/10944967
+plt.ion()
+plt.rcParams.update({
+ 'axes.titlesize': 22,
+ 'text.usetex': True,
+ 'font.family': 'Helvetica'
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 14
+BIGGER_SIZE = 16
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+class DegreePercentageData():
+
+ x_generation_data = []
+ y_percentage_datas = []
+ lines = []
+ DP_FILE_PATH = './out/dp.csv'
+
+ def __init__(self, max_nodes) -> None:
+ self.max_nodes = max_nodes
+ self._setup_plot()
+
+ def save_current_degree_percentages(self, generation, embedding: Embedding):
+ degree_percentages = embedding.get_supernode_degree_percentages()
+ values = [round(value, 2) for value in degree_percentages.values()]
+ self._update_plot(generation, values)
+
+ # Append to file
+ with open(self.DP_FILE_PATH, 'a', newline='') as f:
+ writer = csv.writer(f)
+ row = [generation] + values
+ writer.writerow(row)
+
+ def _setup_plot(self):
+ self.figure, self.ax = plt.subplots()
+
+ # Prepare 2D lines
+ for i in range(self.max_nodes):
+ self.y_percentage_datas.append([])
+
+ # Style plot
+ # https://stackoverflow.com/a/55762294/9655481
+ #linewidth = 5 - 3 * (i / self.max_nodes)
+ #linestyle = ['-', '--', '-.', ':'][i % 4]
+ color = get_supernode_color(i)
+
+ line, = self.ax.plot([], [], color=color, marker='o', markersize=5,
+ label=i, linewidth=1.8)
+ self.lines.append(line)
+
+ plt.xlabel('Generation')
+ plt.ylabel('Super vertices degree percentages')
+ plt.legend()
+
+ # Autoscale on unknown axis and known lims on the other
+ self.ax.set_autoscaley_on(True)
+ self.ax.set_ylim(0.0, 1.1)
+ self.ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
+ # self.ax.set_xlim(0, 100)
+
+ self.ax.grid()
+
+ plt.tight_layout()
+ plt.show(block=False)
+
+ def _update_plot(self, generation, values):
+ # https://stackoverflow.com/a/24272092
+
+ # Set new data
+ self.x_generation_data.append(generation)
+ for i, v in enumerate(values):
+ # Avoid overlapping lines by shifting them a tiny bit
+ prior_values = values[:i]
+ count_v = prior_values.count(v)
+ if count_v:
+ v += 0.010 * count_v
+ self.y_percentage_datas[i].append(v)
+
+ # Update data (with the new *and* the old points)
+ for i, line in enumerate(self.lines):
+ line.set_xdata(self.x_generation_data)
+ line.set_ydata(self.y_percentage_datas[i])
+
+ # Need both of these in order to rescale
+ self.ax.relim()
+ self.ax.autoscale_view()
+
+ # We need to draw *and* flush
+ self.figure.canvas.draw()
+ self.figure.canvas.flush_events()
+
+ def plot_blocking(self):
+ plt.show(block=True)
diff --git a/python/src/results/selection_chances.py b/python/src/results/selection_chances.py
new file mode 100644
index 0000000..06ec52a
--- /dev/null
+++ b/python/src/results/selection_chances.py
@@ -0,0 +1,59 @@
+import matplotlib.pyplot as plt
+import numpy as np
+
+with open('./chances.txt', 'r') as f:
+ line1 = f.readline()
+ line2 = f.readline()
+ p1 = np.fromstring(line1[1:-1], sep=' ')
+ p2 = np.fromstring(line2[1:-1], sep=' ')
+ x = np.arange(len(p1))
+
+# --- Plot setup
+plt.rcParams.update({
+ "text.usetex": True,
+ "font.family": "Helvetica"
+})
+
+# https://stackoverflow.com/a/39566040/9655481
+MEDIUM_SIZE = 8
+MEDIUM_SIZE = 18
+BIGGER_SIZE = 20
+
+plt.rc('font', size=MEDIUM_SIZE) # controls default text sizes
+plt.rc('axes', titlesize=MEDIUM_SIZE) # fontsize of the axes title
+plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
+plt.rc('xtick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('ytick', labelsize=MEDIUM_SIZE) # fontsize of the tick labels
+plt.rc('legend', fontsize=MEDIUM_SIZE) # legend fontsize
+plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
+
+
+width = 0.35 # the width of the bars
+fig, ax = plt.subplots(figsize=(14, 11))
+color_blue = '#2981B3'
+color_red = '#E53054'
+rects1 = ax.bar(x - width/2, p1, width, label='without increase', color=color_blue)
+rects2 = ax.bar(x + width/2, p2, width,
+ label='with increase for small super vertices', color=color_red)
+
+# ax.set_xticks(x, x)
+ax.legend()
+ax.set_ylim(0, 0.5)
+
+ax.bar_label(rects1, padding=3)
+ax.bar_label(rects2, padding=3)
+# fig.tight_layout()
+plt.xlabel('Super vertex')
+plt.ylabel('Chance of selecting the super vertex')
+# plt.title('Selection chances')
+plt.tight_layout()
+plt.show()
+
+# plt.ylim(0, 0.2)
+# plt.plot(x, p1, marker='o', linestyle='--', label='without increase')
+# plt.plot(x, p2, marker='o', linestyle='--', label='with increase for small supernodes')
+# plt.xlabel('Supernodes')
+# plt.ylabel('Chance of selecting a supernode')
+# plt.title('Selection chances')
+# plt.legend()
+# plt.show()
diff --git a/python/src/solver/embedding_solver.py b/python/src/solver/embedding_solver.py
index cdeb4c8..1790bdc 100644
--- a/python/src/solver/embedding_solver.py
+++ b/python/src/solver/embedding_solver.py
@@ -1,128 +1,118 @@
+import logging
import random
+from dataclasses import dataclass
+from typing import Optional
from src.embedding.embedding import Embedding
-from src.graphs.undirected_graphs import UndirectedGraphAdjList
+from src.graph.undirected_graph import UndirectedGraphAdjList
+from src.solver.initialization import Initialization
+from src.solver.supernode_extension import SupernodeExtension
+
+logger = logging.getLogger('evolution')
+
+
+@dataclass
+class EvolutionParams():
+ population_size: int
+ max_mutation_trials: int
+ mutation_extend_to_free_neighbors_probability: float
class EmbeddingSolver():
- def __init__(self, H: UndirectedGraphAdjList):
+ def __init__(self, H: UndirectedGraphAdjList, m, n, t):
self.H = H
if H.nodes_count < 2:
raise NameError('The minor to embed must have at least two nodes')
- self.embedding = Embedding(H)
-
- def init_basic_path(self) -> None:
- """Inits the graph as path graph starting from vertex 0 in the Chimera graph.
- The length is determined by the number of vertices of the minor to embed.
- """
- # Init with path graph as long as H
- # TODO: what if no path graph embedding is possible? When is this the case?
- # Start at vertex 0
- node_from = 0
- for _ in range(self.H.nodes_count-1):
- # Choose random neighbor
- neighbors = self.embedding.get_free_neighbors(node_from)
- node_to = random.choice(neighbors)
-
- # Embed
- self.embedding.embed_edge(node_from, node_to)
-
- node_from = node_to
+ self._embedding = Embedding(H, m, n, t)
+ self.initialization = Initialization(self._embedding)
+ self._supernode_extension = SupernodeExtension(self._embedding)
- self.embedding.try_to_add_missing_edges()
+ def initialize_embedding(self):
+ self.initialization.init_dfs()
+ self._local_maximum()
def get_embedding(self):
- return self.embedding.get_embedding()
-
- def _add_random_chain(self):
- # --- Randomly collapse two nodes to one
- nodes_embedded = self.embedding.get_embedded_nodes()
- # TODO: make sure we don't use nodes that are already in a chain
- from_node = random.choice(nodes_embedded)
- node_tos = self.embedding.get_connected_neighbors(from_node)
- to_node = random.choice(node_tos)
- print(f'Trying to chain nodes {from_node} and {to_node}')
-
- # --- Adjust so that new chain is viable
- # find new place for previous node_to in the graph
- # so that the layout permits the following edges
- # node_to --- node_to'
- # node_to' --- all_nodes reachable from node_to
- to_node_free_neighbors = self.embedding.get_free_neighbors(to_node)
- to_node_connected_neighbors = self.embedding.get_connected_neighbors(
- to_node)
-
- # --- 1) Try out all possible positions for node_to_new
- for to_node_new in to_node_free_neighbors:
- print(f'node_to_new: {to_node_new}')
-
- # from node_to_new: can we reach all nodes previously connected to node_to?
- node_to_new_reachable_neighbors = self.embedding.get_reachable_neighbors(
- to_node_new)
- can_reach = [neighbor in node_to_new_reachable_neighbors
- for neighbor in to_node_connected_neighbors if neighbor != from_node]
- if all(can_reach):
- # Try out on playground
- playground = self.embedding.get_playground()
- playground.add_chain_to_used_nodes(
- from_node, to_node, to_node_new)
- playground.try_to_add_missing_edges()
- return playground
-
- # --- 2) If step 1) did not work, try to construct another new chain (-> two chains in total)
- to_node_new = to_node_free_neighbors[0]
- to_node_new_free_neighbors = self.embedding.get_free_neighbors(
- to_node_new)
- to_node_new_chain_partner = to_node_new_free_neighbors[0]
-
- # from to_node_new AND to_node_new_chain_partner:
- # Can we now reach all nodes previously connected to node_to
- chain_reachable_nodes = self.embedding.get_reachable_neighbors(
- to_node_new)
- chain_reachable_nodes.extend(
- self.embedding.get_reachable_neighbors(to_node_new_chain_partner))
- can_reach = [neighbor in chain_reachable_nodes
- for neighbor in to_node_connected_neighbors if neighbor != from_node]
- if all(can_reach):
- # Try out on playground
- playground = self.embedding.get_playground()
-
- playground.extend_one_node_to_chain(
- to_node_new, to_node_new_chain_partner, extend_G=to_node)
-
- # edge to_node---to_node_new
- # will be removed when adding this chain:
- playground.add_chain_to_used_nodes(
- from_node, to_node, to_node_new)
-
- print(
- f'to_node_new to chain partner: {to_node_new}---{to_node_new_chain_partner}')
- playground.try_to_add_missing_edges()
- return playground
-
- # 3. If all of that fails, mark the mutation as failed
+ return self._embedding.get_embedding(G_to_H_mapping=True)
+
+ def commit(self, playground: Embedding):
+ self._embedding = playground
+ self._supernode_extension = SupernodeExtension(self._embedding)
+
+ def generate_population_and_select(self, params: EvolutionParams) -> Optional[Embedding]:
+ """Generates a new population & selects and returns the best individual
+ from it."""
+ population = self._generate_children(params)
+ if not population:
+ population = self.last_trial(params)
+ if not population:
+ logger.info(f'🔳 Population generation failed')
+ return None
+
+ if len(population) < params.population_size:
+ logger.info(f'🔳 {params.max_mutation_trials} mutations to construct '
+ ' a new child failed, will return a smaller population: '
+ f'{len(population)}/{params.population_size}')
+
+ selected_population = self._select_best_child(population)
+ return selected_population
+
+ def last_trial(self, params: EvolutionParams) -> Optional[list[Embedding]]:
+ """Try to remove unnecessary supernode nodes and generate a new population"""
+ logger.info(f'🔳 Last trial, remove redundant nodes')
+ self._embedding.remove_redundancy()
+ return self._generate_children(params)
+
+ def _generate_children(self, params: EvolutionParams) -> list[Embedding]:
+ """Generates children (Embeddings) for one population."""
+ population = [] # list of Embeddings
+
+ for i in range(params.population_size):
+ child = self._generate_child(params, i)
+ if child:
+ population.append(child)
+ else:
+ # early return as it is unlikely that we will be able
+ # to generate more children
+ return population
+
+ return population
+
+ def _generate_child(self, params: EvolutionParams, child_number: int) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'--- Try find a new viable mutation')
+
+ for _ in range(params.max_mutation_trials):
+ logger.info('--- MUTATION')
+ if random.random() < params.mutation_extend_to_free_neighbors_probability:
+ mutation = self._supernode_extension.extend_random_supernode_to_free_neighbors()
+ else:
+ mutation = self._supernode_extension.extend_random_supernode()
+
+ if mutation:
+ logger.info(f'💚 Valid mutation for child {child_number}')
+ return mutation
+
+ logger.info(f'🔳 All {params.max_mutation_trials} mutations failed, '
+ 'could not construct a child -> Abort')
return None
- def mutate(self):
- """
- Mutates the embedding. Supports adding random chains rights now.
- """
- print('--- MUTATION')
- # --- Delete & Insert edge
- # Delete an edge between two random nodes that were already embedded.
- # Insert a new edge between two other random nodes that were already embedded.
+ def _select_best_child(self, population: list[Embedding]):
+ logger.info('')
+ logger.info('Select best child')
- # Add random chain
- return self._add_random_chain()
+ # Try to optimize to local maximum first
+ improvements = []
+ for i, child in enumerate(population):
+ logger.info(f'💚 Checking local optima for child {i}')
+ improvements.append(child.try_embed_missing_edges())
- # TODO: Remove chain mutation
+ best_child_index = improvements.index(max(improvements))
+ return population[best_child_index]
- # --- Perspective change
- # TODO: with low probability: view reduced graph from completely different view
- # maybe from this perspective, we can leverage some better mutations
- # and reduce the costs faster
+ def _local_maximum(self) -> int:
+ return self._embedding.try_embed_missing_edges()
def found_embedding(self) -> bool:
- return self.embedding.is_valid_embedding()
+ return self._embedding.is_valid_embedding()
diff --git a/python/src/solver/evolution.py b/python/src/solver/evolution.py
index fbc9506..6fdc161 100644
--- a/python/src/solver/evolution.py
+++ b/python/src/solver/evolution.py
@@ -1,58 +1,182 @@
-from src.drawing.draw import Draw
-from src.graphs.undirected_graphs import UndirectedGraphAdjList
-from src.solver.embedding_solver import EmbeddingSolver
-
-
-def init_H():
- # K4 graph
- H = UndirectedGraphAdjList(4)
- H._set_edge(0, 1)
- H._set_edge(0, 2)
- H._set_edge(0, 3)
- H._set_edge(1, 2)
- H._set_edge(1, 3)
- H._set_edge(2, 3)
- return H
-
-
-def main():
- print('--- Main ---')
-
- # --- Setup
- d = Draw()
- H = init_H()
- d.draw_chimera_graph(1, 1, 4) # one unit cell of Chimera graph
-
- # --- Start solving
- solver = EmbeddingSolver(H)
- solver.init_basic_path()
- found_embedding = solver.found_embedding()
- if found_embedding:
- print('✨🎉 Found embedding')
- return
-
- # --- Mutation
- playground = solver.mutate()
- if not playground:
- print('Not a viable mutation')
- return
-
- # --- Output
- print()
- print('--- Output ---')
- nodes, edges = playground.get_embedding()
- mapping = playground.get_mapping_H_to_G()
-
- print('*** Final mapping ***')
- print(mapping)
- print('*** Final embedding ***')
- print(nodes)
- print(edges)
- print(f'Is correct: {playground.is_valid_embedding()}')
-
- mapping_G_to_H = playground.get_mapping_G_to_H()
- d.draw_embedding(nodes, edges, mapping_G_to_H)
+import logging
+import os
+import shutil
+import signal
+from random import random
+from typing import Optional
+
+from src.drawing.draw import DrawEmbedding
+from src.embedding.embedding import Embedding
+from src.graph.test_graph import TestGraph
+from src.results.degree_percentage import DegreePercentageData
+from src.solver.embedding_solver import EmbeddingSolver, EvolutionParams
+from src.util.logging import init_logger
+
+init_logger()
+logger = logging.getLogger('evolution')
+
+stop = False
+
+
+################################# Params #######################################
+
+params = EvolutionParams(
+ population_size=12,
+ max_mutation_trials=30,
+ mutation_extend_to_free_neighbors_probability=0.3 # should be <=0.5
+)
+
+max_total = 1
+max_generations = 1000
+remove_redundancy_probability = 0.01
+
+# Chimera graph
+m = 2 # grid size
+n = 2 # grid size
+t = 4 # shore size
+
+
+################################ Setup ########################################
+
+H = TestGraph.crossed_house()
+solver = EmbeddingSolver(H, m, n, t)
+dp = DegreePercentageData(len(H.get_nodes()))
+
+
+############################### Evolution ######################################
+
+def main_loop():
+ for i in range(max_total):
+ logger.info('')
+ logger.info('#############')
+ logger.info('🎈 NEW MAIN 🎈')
+ logger.info('#############')
+ logger.info('')
+ logger.info(f'Calling main: {i}')
+
+ d = DrawEmbedding(m, n, t)
+ res = main(d)
+ save_final(d)
+ if res:
+ break
+ dp.plot_blocking()
+
+
+def signal_handler(sig, frame):
+ # https://stackoverflow.com/questions/1112343/how-do-i-capture-sigint-in-python
+ global stop
+ stop = True
+
+
+def main(d: DrawEmbedding) -> bool:
+ # logger.info('--- Main ---')
+
+ # --- Clear
+ try:
+ shutil.rmtree('./out/')
+ except FileNotFoundError:
+ pass
+ os.mkdir('./out')
+
+ # --- Init
+ solver.initialize_embedding()
+ save_embedding(*solver.get_embedding(), d, 'initial',
+ title=f'Initial embedding')
+ dp.save_current_degree_percentages(-1, solver._embedding)
+
+ if solver.found_embedding():
+ logger.info('🎉 Directly found embedding after initialization')
+ print('🎉 Directly found embedding after initialization')
+ # save_final(d)
+ output_embedding(*solver.get_embedding(), d)
+ return True
+
+ # --- Start solver
+ for i in range(max_generations):
+ if stop:
+ print('Stop spawning new generations')
+ break
+
+ child = do_one_generation(i, solver)
+
+ if not child:
+ logger.info('🔳 Stopping algorithm...')
+ return False
+
+ solver.commit(child)
+
+ # Save embedding every x steps
+ save_embedding_steps = 1
+ if (i % save_embedding_steps == 0) \
+ or (i == max_generations - 2) or (i == max_generations - 1):
+ save_embedding(*solver.get_embedding(), d, str(i),
+ title=f'Generation {i}')
+
+ # Save degree percentage data
+ dp.save_current_degree_percentages(i, solver._embedding)
+
+ # Check if done
+ if child.is_valid_embedding():
+ save_embedding(*solver.get_embedding(), d, str(i),
+ title=f'Generation {i} (final)')
+ child.remove_redundancy()
+ save_embedding(*solver.get_embedding(), d, f'{i}final',
+ title=f'Generation {i} (final with redundancy removed)')
+ logger.info('🎉🎉🎉🎉🎉🎉 Found embedding')
+ print('🎉🎉🎉🎉🎉🎉 Found embedding')
+ return True
+ else:
+ logger.info('✅ Generation passed')
+
+ return False
+
+
+def do_one_generation(i: int, solver: EmbeddingSolver) -> Optional[Embedding]:
+ logger.info('')
+ logger.info(f'🔄 Generation: {i}')
+
+ child = solver.generate_population_and_select(params)
+ if not child:
+ return None
+
+ # Leave "room" on graph for next generation
+ if random() < remove_redundancy_probability:
+ child.remove_redundancy()
+
+ return child
+
+
+################################ Output ########################################
+
+def output_embedding(nodes, edges, mapping_G_to_H, d: DrawEmbedding):
+ logger.info('*** Embedding ***')
+ logger.info(nodes)
+ logger.info(edges)
+ logger.info(mapping_G_to_H)
+
+ d.draw_chimera_and_embedding(nodes, edges, mapping_G_to_H)
+ d.show_embedding()
+
+
+def save_embedding(nodes: set[int], edges: set[tuple[int, int, int]],
+ mapping_G_to_H, d: DrawEmbedding, i: str, title=''):
+ logger.info('')
+ logger.info('🎈 Current embedding')
+ logger.info(f'edges: {edges}')
+ logger.info(f'mapping_G_to_H: {mapping_G_to_H}')
+
+ d.draw_whole_embedding_step(nodes, edges, mapping_G_to_H, title=title)
+ d.save_and_clear(f'./out/{i}.svg')
+
+
+def save_final(d: DrawEmbedding) -> None:
+ logger.info('Save final')
+ pass
+ # d.save_and_clear(f'./out/steps.svg')
+
+ ################################ Main ##########################################
if __name__ == "__main__":
- main()
+ signal.signal(signal.SIGINT, signal_handler)
+ main_loop()
diff --git a/python/src/solver/initialization.py b/python/src/solver/initialization.py
new file mode 100644
index 0000000..d3b407b
--- /dev/null
+++ b/python/src/solver/initialization.py
@@ -0,0 +1,127 @@
+import logging
+import random
+
+from src.embedding.embedding import Embedding
+from src.util.stack import Stack
+from src.util.util import get_first_from
+
+logger = logging.getLogger('evolution')
+
+
+class Initialization():
+
+ def __init__(self, embedding: Embedding) -> None:
+ self._embedding = embedding
+
+ def init_basic_path(self) -> None:
+ """Inits the graph as path graph starting from vertex 0 in the Chimera graph.
+ The length is determined by the number of vertices of the minor to embed.
+ """
+ # Init with path graph as long as H
+ # TODO: what if no path graph embedding is possible? When is this the case?
+ # Start at vertex 0
+
+ source = 0
+ for _ in range(self._embedding.H.nodes_count-1):
+ # Choose random neighbor
+ neighbors = self._embedding.get_free_neighbors(source)
+ target = random.choice(list(neighbors))
+
+ # Embed
+ self._embedding.embed_edge(source, target)
+
+ source = target
+
+ def init_bfs(self):
+ """Traverses through H and inits graph H usugin breadth first search on H."""
+ # Mark all vertices as not visited
+ visited = [False] * self._embedding.H.nodes_count
+
+ queue = []
+
+ # Mark source node as visited
+ h = 0 # start with node 0 in graph H
+ queue.append(h)
+ visited[h] = True
+
+ while queue:
+ # Dequeue node & get neighbors
+ h = queue.pop(0)
+ neighbors_h = self._embedding.H.get_neighbor_nodes(h)
+ # Filter out already visited nodes in H
+ neighbors_h = [h for h in neighbors_h
+ if not visited[h]]
+
+ # Embed edges to all neighbors
+ if h == 0:
+ g = 0 # start with node 0 for embedding in graph G
+ else:
+ gs = self._embedding.get_nodes_G(h)
+ g = get_first_from(gs)
+
+ free_neighbors_g = self._embedding.get_free_neighbors(g)
+ if len(free_neighbors_g) < len(neighbors_h):
+ raise RuntimeError(
+ 'Not enough free neighbors to embed node of H in G (breadth first search)')
+
+ for neighbor_h in neighbors_h:
+ neighbor_h_on_g = self._embedding.get_nodes_G(
+ neighbor_h)
+ # Neighbor already embedded embedded?
+ if neighbor_h_on_g:
+ # Try to add edge
+ if self._embedding.exists_edge(g, neighbor_h_on_g):
+ self._embedding.embed_edge_with_mapping(
+ h, g, neighbor_h, neighbor_h_on_g)
+ else:
+ # do nothing (this edge is added later using chains)
+ pass
+ else:
+ # Choose random free neighbor
+ to_g = random.choice(list(free_neighbors_g))
+ free_neighbors_g.remove(to_g)
+
+ # Embed
+ self._embedding.embed_edge_with_mapping(
+ h, g, neighbor_h, to_g)
+ logger.info(f'Embedded edge: {g}-{to_g}')
+
+ # Prepare queue to continue with adjacent nodes
+ queue.append(neighbor_h)
+ visited[h] = True
+
+ def init_dfs(self):
+ """Inits G using depth first search."""
+ visited = [False] * self._embedding.H.nodes_count
+ recursion_stack = Stack()
+ self._dfs(0, visited, recursion_stack) # start with node 0
+
+ def _dfs(self, to_h, visited, recursion_stack: Stack):
+ """Depth first search recurion"""
+ # Update status (visited array & recursion stack)
+ from_h = recursion_stack.peek() # peek first
+ recursion_stack.push(to_h) # then push
+ visited[to_h] = True
+
+ if from_h != None: # from_h is None at the initial call of dfs()
+ # Get from_g
+ if from_h == 0:
+ from_g = 0
+ else:
+ from_g = self._embedding.get_nodes_G(from_h)
+ from_g = get_first_from(from_g) # no chains yet
+
+ free_neighbors_g = self._embedding.get_free_neighbors(from_g)
+ to_g = random.choice(list(free_neighbors_g))
+
+ # Embed
+ self._embedding.embed_edge_with_mapping(
+ from_h, from_g, to_h, to_g)
+
+ # DFS recursion
+ neighbors_h = self._embedding.H.get_neighbor_nodes(to_h)
+ for neighbor_h in neighbors_h:
+ if not visited[neighbor_h]:
+ self._dfs(neighbor_h, visited, recursion_stack)
+
+ recursion_stack.pop()
diff --git a/python/src/solver/k4_results.py b/python/src/solver/k4_results.py
index 4772ee5..b9153c5 100644
--- a/python/src/solver/k4_results.py
+++ b/python/src/solver/k4_results.py
@@ -1,17 +1,17 @@
from src.drawing.draw import Draw
-from src.graphs.undirected_graphs import UndirectedGraphAdjList
+from src.graph.undirected_graph import UndirectedGraphAdjList
from src.solver.embedding_solver import EmbeddingSolver
def init_H():
# K4 graph
H = UndirectedGraphAdjList(4)
- H._set_edge(0, 1)
- H._set_edge(0, 2)
- H._set_edge(0, 3)
- H._set_edge(1, 2)
- H._set_edge(1, 3)
- H._set_edge(2, 3)
+ H.set_edge(0, 1)
+ H.set_edge(0, 2)
+ H.set_edge(0, 3)
+ H.set_edge(1, 2)
+ H.set_edge(1, 3)
+ H.set_edge(2, 3)
return H
@@ -47,7 +47,7 @@ def main():
return
# --- Output
- nodes, edges = playground.get_embedding()
+ nodes, edges, mapping_G_to_H = playground.get_embedding()
length1 = len(found_embeddings)
found_embeddings.add(frozenset(edges))
@@ -58,7 +58,6 @@ def main():
continue
print(f'{i}: Is correct: {playground.is_valid_embedding()}')
- mapping_G_to_H = playground.get_mapping_G_to_H()
d.draw_to_big_plot(nodes, edges, mapping_G_to_H)
i += 1
diff --git a/python/src/solver/supernode_extension.py b/python/src/solver/supernode_extension.py
new file mode 100644
index 0000000..9ffcfde
--- /dev/null
+++ b/python/src/solver/supernode_extension.py
@@ -0,0 +1,324 @@
+import logging
+import random
+from collections import namedtuple
+from dataclasses import dataclass
+from typing import Optional
+
+import numpy as np
+from src.embedding.articulation_point import ArticulationPointCalculator
+from src.embedding.embedding import Embedding, NoFreeNeighborNodes
+from src.util.util import any_of_one_in_other, get_first_from
+
+SourceTargetPair = namedtuple('SourceTargetPair', 'source target')
+logger = logging.getLogger('evolution')
+
+
+@dataclass
+class TargetParams():
+ target: int
+ target_supernode: int
+ shifted_target: int
+ target_neighbors: set[int]
+
+
+class SupernodeExtension():
+
+ def __init__(self, embedding: Embedding) -> None:
+ self._embedding = embedding
+ self._non_viable_extensions = []
+ self.selection_chances = []
+
+ def extend_random_supernode_to_free_neighbors(self) -> Optional[Embedding]:
+ """Chooses a random supernode and extends it to a free neighbor."""
+ logger.info('Trying to extend random supernode to free neighbors')
+ playground = self._embedding.get_playground()
+
+ supernode = self._choose_random_supernode_with_bias()
+ supernode_nodes = self._embedding.get_nodes_in_supernode(supernode)
+
+ max_trials = 10
+ tried_nodes = set()
+ for _ in range(min(len(supernode_nodes), max_trials)):
+ source = random.choice(list(supernode_nodes - tried_nodes))
+
+ try:
+ free_neighbors = playground.get_free_neighbors(source)
+ except:
+ tried_nodes.add(source)
+ continue
+
+ target = random.choice(list(free_neighbors))
+ playground.construct_supernode(source, target)
+ logger.info(f'-> Extended node {source} (supernode: {supernode}) to {target}')
+ return playground
+
+ logger.info(f'-> ❌ failed (for supernode {supernode})')
+ return None
+
+ def _choose_random_supernode_with_bias(self) -> int:
+ """Randomly chooses a supernode from H such that supernodes, which have
+ the least number of edges to other supernodes embedded in G, are favored.
+ We also favor supernodes that have the smallest number of nodes.
+ Thus, we won't pick an element according to a uniform distribution, but to
+ a custom one (using numpy).
+ """
+ supernodes = list(self._embedding.get_nodes_H())
+
+ if not len(self.selection_chances):
+ degree_percentages = self._embedding.get_supernode_degree_percentages()
+
+ # Favor smaller supernodes
+ # Those get assigned an increased chance of being selected
+ max_favor_small_supernodes = 0.7 * max(degree_percentages.values())
+ lin_increases = np.linspace(
+ max_favor_small_supernodes, 0, num=len(supernodes))
+ supernodes_sorted = self._embedding.get_sorted_supernodes_by_size()
+ # we use the supernodes as indices for the linspace of increases here
+ increases = [lin_increases[node] for node in supernodes_sorted]
+
+ # Calculate selection chances
+ selection_chances = np.array([(1-p) for p in degree_percentages.values()])
+ selection_chances_without_increase = np.copy(selection_chances)
+
+ # Norm
+ sum = np.sum(selection_chances_without_increase)
+ if sum != 0:
+ selection_chances_without_increase *= 1 / \
+ np.sum(selection_chances_without_increase)
+ selection_chances += increases
+ selection_chances *= 1 / np.sum(selection_chances)
+ self.selection_chances = selection_chances
+
+ np.set_printoptions(precision=2)
+ logger.info(
+ f'Selection chances (without increases) are: {selection_chances_without_increase}')
+ logger.info(f'Selection chances are: {selection_chances}')
+
+ # Choose according to calculated chances
+ supernode = np.random.choice(supernodes, p=self.selection_chances)
+ return supernode
+
+ def extend_random_supernode(self) -> Optional[Embedding]:
+ """Chooses a random supernode and extends it to an already embedded
+ neighbor node by "bumping" the neighbor to one of its free neighbors.
+
+ When the embedded neighbor is bumped to a free neighbor, this algorithm
+ might construct another supernode for the neighbor in order to reach
+ every node that could previously be reached from the neighbor node."""
+ pair = self._choose_source_and_target()
+ if not pair:
+ return None
+ source, target = pair.source, pair.target
+ logger.info(f'🔗🔗 Trying to construct: {source}, {target}')
+ if (source, target) in self._non_viable_extensions:
+ logger.info('❌ Already considered but not viable -> skip')
+ # TODO: Don't count this case as wasted mutation
+ return None
+
+ try:
+ target_free_neighbors = self._embedding.get_free_neighbors(target)
+ except NoFreeNeighborNodes:
+ logger.info(f'❌ Target {target} has no free neighbors')
+ return None
+
+ playground = self._embedding.get_playground()
+
+ # --- Try out possible positions for shifted_target
+ # Always check if we can reach all super nodes previously connected
+ # to target from the shifted_target
+ target_neighbors = playground.get_embedded_neighbors(target)
+ target_neighbors.discard(source) # no need to reach source from shifted_target
+ target_supernode = playground.get_supernode(target)
+ logger.info(f'Target neighbors are: {target_neighbors}')
+
+ for shifted_target in target_free_neighbors:
+ logger.info(f'▶ Try out shifted target on node: {shifted_target}')
+ p = TargetParams(target, target_supernode, shifted_target, target_neighbors)
+ res = self._construct_supernode_with_shifted_target(source, p)
+ if res:
+ return res
+
+ # If it didn't work, mark the mutation as failed
+ self._non_viable_extensions.append((source, target))
+ logger.info('❌ No viable supernode placement')
+ return None
+
+ def _choose_random_embedded_node(self) -> int:
+ embedded_nodes = self._embedding.get_embedded_nodes()
+ node = random.choice(list(embedded_nodes))
+ return node
+
+ def _construct_supernode_with_shifted_target(self,
+ source: int,
+ p: TargetParams) -> Optional[Embedding]:
+ """Tries to embed the shifted target, so that the node placement is viable.
+
+ This means that we check if the new place for ``target`` - which is
+ ``shifted_target`` - allows for the following edges:
+ - ``target`` - ``shifted_target``
+ - ``shifted_target`` - ``target_neighbors`` (all embedded ``target`` neighbors)
+ """
+ playground = self._embedding.get_playground()
+ # Get reachable neighbors
+ # has to be calculated prior to supernode handover (!)
+ shifted_target_reachable = playground.get_reachable_neighbors(p.shifted_target)
+ shifted_target_reachable.discard(source)
+ shifted_target_reachable.discard(p.target)
+
+ # supernode handover from target to shifted_target
+ playground.construct_supernode(p.target, p.shifted_target)
+ playground.construct_supernode(source, p.target)
+
+ if not p.target_neighbors:
+ logger.info(f'No target neighbors to check: {p.target_neighbors}')
+ return playground
+
+ # Check that previous connections still work
+ # 1st strategy
+ neighbors_done = self._construct_with_one_chain(playground, p, shifted_target_reachable)
+ # 2nd strategy (complementing 1st strategy)
+ if not len(neighbors_done) == len(p.target_neighbors):
+ worked = self._construct_with_another_chain(playground, source, p, neighbors_done)
+ if not worked:
+ return None
+
+ # Check if strategy really worked
+ if playground.check_supernode_connectiveness(p.target_supernode):
+ return playground
+ else:
+ logger.info(f'Supernode sanity not ensured.')
+ return None
+
+ def _construct_with_one_chain(self, playground: Embedding, p: TargetParams,
+ shifted_target_reachable: set[int]) -> set[int]:
+ """Tries to construct the supernode extension with just one chain."""
+ neighbors_done = set()
+
+ for neighbor in p.target_neighbors:
+ target_neighbor = self.get_reachable_node_in_neighbor_supernode(
+ playground, neighbor, {p.shifted_target}, shifted_target_reachable)
+
+ if target_neighbor != None: # might be node "0"
+ logger.info(f'Could reach {target_neighbor}')
+ neighbors_done.add(neighbor)
+ playground.embed_edge(p.shifted_target, target_neighbor)
+ else:
+ logger.info(f'Could not reach '
+ f'(reachable nodes are: {shifted_target_reachable})')
+ # Continue normally with next neighbor as next one might be
+ # reachable with this strategy (we then try to reach the
+ # remaining neighbors with the next strategy).
+
+ return neighbors_done
+
+ def _construct_with_another_chain(self, playground: Embedding, source: int,
+ p: TargetParams, neighbors_done: set[int]) -> bool:
+ """Tries to construct another chain to see if we can reach
+ remaining neighbors."""
+ try:
+ shifted_target_free_neighbors = playground.get_free_neighbors(
+ p.shifted_target)
+ except NoFreeNeighborNodes:
+ logger.info(f'Could not construct another supernode '
+ f'from shifted_target: {p.shifted_target} '
+ f'(no free neighbor of shifted_target)')
+ return None
+ shifted_target_partner = get_first_from(shifted_target_free_neighbors)
+
+ logger.info(f'🔗 Trying to construct another supernode: '
+ f'{p.shifted_target}, {shifted_target_partner}')
+ # Chain shifted target and shifted target partner
+ # prior to calling this, we need to make sure that shifted_target
+ # now has the prior supernode of target
+ # The call itself needs to take place prior to embedding edges outgoing
+ # from shifted_target_partner (otherwise shifted_target_partner would
+ # not have a viable supernode)
+ playground.construct_supernode(p.shifted_target, shifted_target_partner)
+
+ # Do not try to compute shifted_target reachable again here (!)
+ # as these are different now since shifted_target has the previous
+ # supernode of target
+ shifted_target_partner_reachable = playground.get_reachable_neighbors(
+ shifted_target_partner)
+ shifted_target_partner_reachable.discard(source)
+ shifted_target_partner_reachable.discard(p.target)
+
+ for neighbor in p.target_neighbors:
+ # Already checked neighbors with the one-chain strategy
+ if neighbor in neighbors_done:
+ continue
+
+ target_neighbor = self.get_reachable_node_in_neighbor_supernode(
+ playground, neighbor, {p.shifted_target, shifted_target_partner},
+ shifted_target_partner_reachable)
+
+ if target_neighbor != None:
+ logger.info(f'Could reach (with 2nd chain) {target_neighbor}')
+ playground.embed_edge(shifted_target_partner, target_neighbor)
+ else:
+ logger.info(f'Could also not reach (reachable nodes are: '
+ f'{shifted_target_partner_reachable})')
+ return False # did not achieve a viable mutation even with 2nd strategy
+
+ return True
+
+ def get_reachable_node_in_neighbor_supernode(self, playground: Embedding,
+ neighbor: int, ignore_neighbors: set[int],
+ reachable: set[int]) -> Optional[int]:
+ """We need to discard some nodes here as they are not actually part of the
+ neighbor supernode. This is because we construct supernodes first to be
+ able to embed edges correctly. However, we then need to compare with
+ the a priori state and not this temporary state, which is why we
+ have to discard some nodes."""
+ neighbor_supernode = playground.get_supernode(neighbor)
+ neighbor_supernode_nodes = playground.get_nodes_in_supernode(neighbor_supernode)
+ for ignore in ignore_neighbors:
+ neighbor_supernode_nodes.discard(ignore)
+
+ logger.info(f'? Can we reach neighbor {neighbor} '
+ f'(supernode: {neighbor_supernode} -> {neighbor_supernode_nodes})')
+ reachable_neighbor = any_of_one_in_other(reachable, neighbor_supernode_nodes)
+ return reachable_neighbor
+
+ def _choose_source_and_target(self) -> Optional[SourceTargetPair]:
+ supernode = self._choose_random_supernode_with_bias()
+ supernode_nodes = self._embedding.get_nodes_in_supernode(supernode)
+
+ max_trials = 5
+ for _ in range(max_trials):
+ source = random.choice(list(supernode_nodes))
+ target = self._choose_neighbor_not_in_same_supernode(source, supernode)
+ if target:
+ return SourceTargetPair(source, target)
+
+ logger.info(f'❌ Could not find a valid source/target pair')
+ return None
+
+ def _choose_neighbor_not_in_same_supernode(self, source: int,
+ source_supernode: int) -> Optional[int]:
+ """Tries to randomly choose a neighbor (target) for the given source node
+ that is not in the same supernode as the source node AND that is not
+ an articulation point in its own supernode.
+ Returns nothing if this condition cannot be met for the given source node
+ and its neighbors."""
+ targets_orig = self._embedding.get_embedded_neighbors(source)
+ targets = []
+ for target in targets_orig:
+ # Is target in the same supernode as source?
+ if self._embedding.get_supernode(target) == source_supernode:
+ continue
+
+ # Is target an articulation point?
+ target_supernode_nodes = self._embedding.get_nodes_in_supernode_of(target)
+ articulation_points = ArticulationPointCalculator(self._embedding.G_embedding)\
+ .calc_articulation_points(target_supernode_nodes)
+ if target in articulation_points:
+ continue
+
+ targets.append(target)
+
+ if not targets:
+ return None
+
+ target = random.choice(list(targets))
+ return target
diff --git a/python/src/util/logging.py b/python/src/util/logging.py
new file mode 100644
index 0000000..71070b8
--- /dev/null
+++ b/python/src/util/logging.py
@@ -0,0 +1,32 @@
+import logging
+import logging.handlers
+import os
+
+
+def disable_logger():
+ logging.disable(logging.CRITICAL)
+
+
+def init_logger():
+ logger = logging.getLogger('evolution')
+ logger.setLevel(logging.DEBUG)
+
+ # File handler
+ if not os.path.exists('./logs'):
+ os.mkdir('./logs/')
+ log_filename = './logs/evolution.log'
+ should_roll_over = os.path.isfile(log_filename)
+ log_handler = logging.handlers.RotatingFileHandler(
+ log_filename, mode='w', backupCount=100, encoding='utf-8', delay=True)
+ if should_roll_over:
+ log_handler.doRollover()
+ log_handler.setLevel(logging.DEBUG)
+
+ logger.addHandler(log_handler)
+
+ # write to stderr
+ console_handler = logging.StreamHandler()
+ console_handler.setLevel(logging.WARNING)
+ logging.getLogger().addHandler(console_handler)
+
+# disable_logger()
diff --git a/python/src/util/stack.py b/python/src/util/stack.py
new file mode 100644
index 0000000..2e8cbd1
--- /dev/null
+++ b/python/src/util/stack.py
@@ -0,0 +1,16 @@
+class Stack:
+ def __init__(self):
+ self.stack = []
+
+ def push(self, data):
+ self.stack.append(data)
+
+ def peek(self):
+ if self.stack:
+ return self.stack[-1]
+ return None
+
+ def pop(self):
+ if self.stack:
+ return self.stack.pop()
+ return None
diff --git a/python/src/util/util.py b/python/src/util/util.py
new file mode 100644
index 0000000..3df3807
--- /dev/null
+++ b/python/src/util/util.py
@@ -0,0 +1,16 @@
+from typing import Optional
+
+
+def get_first_from(s: set[int]) -> int:
+ # https://stackoverflow.com/a/48874729/9655481
+ for e in s:
+ return e
+ raise KeyError('Set is empty')
+
+
+def any_of_one_in_other(set1: set[int], set2: set[int]) -> Optional[int]:
+ # https://stackoverflow.com/a/16138094/9655481
+ for element in set1:
+ if element in set2:
+ return element
+ return None
diff --git a/python/tests/test_embedding_solver.py b/python/tests/test_embedding_solver.py
index e44edbd..f6ed8e8 100644
--- a/python/tests/test_embedding_solver.py
+++ b/python/tests/test_embedding_solver.py
@@ -1,45 +1,45 @@
-import unittest
-from unittest.case import TestCase
-
-from src.embedding_solver import EmbeddingSolver
-from src.graphs.undirected_graphs import UndirectedGraphAdjList
-
-
-class Test_EmbeddingSolver(TestCase):
-
- def test_init_basic_path(self):
- for i in range(0, 8):
- for j in range(10):
- H = UndirectedGraphAdjList(i) # init minor
- if i < 2:
- self.assertRaises(NameError, EmbeddingSolver, H)
- continue
- solver = EmbeddingSolver(H)
- solver.init_basic_path()
- nodes, edges = solver.get_embedding()
- self.assertEqual(len(nodes), i)
-
- def test_cost_stay_the_same_for_same_inits(self):
- cost_fixed = -1
-
- for i in range(20):
- H = UndirectedGraphAdjList(5)
- H._set_edge(0, 1)
- H._set_edge(1, 2)
- H._set_edge(1, 3)
- H._set_edge(2, 3)
- H._set_edge(3, 4)
- H._set_edge(4, 0)
-
- solver = EmbeddingSolver(H)
- solver.init_basic_path()
- cost = solver.calculate_cost()
-
- if i == 0:
- cost_fixed = cost
- else:
- self.assertEqual(cost, cost_fixed)
-
-
-if __name__ == '__main__':
- unittest.main()
+# import unittest
+# from unittest.case import TestCase
+
+# from src.graphs.undirected_graph import UndirectedGraphAdjList
+# from src.solver.embedding_solver import EmbeddingSolver
+
+
+# class Test_EmbeddingSolver(TestCase):
+
+# def test_init_basic_path(self):
+# for i in range(0, 8):
+# for j in range(10):
+# H = UndirectedGraphAdjList(i) # init minor
+# if i < 2:
+# self.assertRaises(NameError, EmbeddingSolver, H)
+# continue
+# solver = EmbeddingSolver(H)
+# solver.init_basic_path()
+# nodes, edges = solver.get_embedding()
+# self.assertEqual(len(nodes), i)
+
+# def test_cost_stay_the_same_for_same_inits(self):
+# cost_fixed = -1
+
+# for i in range(20):
+# H = UndirectedGraphAdjList(5)
+# H.set_edge(0, 1)
+# H.set_edge(1, 2)
+# H.set_edge(1, 3)
+# H.set_edge(2, 3)
+# H.set_edge(3, 4)
+# H.set_edge(4, 0)
+
+# solver = EmbeddingSolver(H)
+# solver.init_basic_path()
+# cost = solver.calculate_cost()
+
+# if i == 0:
+# cost_fixed = cost
+# else:
+# self.assertEqual(cost, cost_fixed)
+
+
+# if __name__ == '__main__':
+# unittest.main()
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 219db95..cf20f98 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,6 @@
add_subdirectory(common)
+add_subdirectory(lmrp)
add_subdirectory(evolutionary)
add_subdirectory(initial)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index eaaaed4..ff8e787 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,9 +1,16 @@
target_sources(majorminer PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/debug_utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/utils.cpp
${CMAKE_CURRENT_SOURCE_DIR}/graph_gen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cut_vertex.cpp
${CMAKE_CURRENT_SOURCE_DIR}/embedding_validator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/embedding_visualizer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/embedding_analyzer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/embedding_state.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/embedding_manager.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/csc_problem.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/random_gen.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/time_measurement.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/graph_info.cpp
)
diff --git a/src/config.hpp b/src/common/config.hpp
similarity index 85%
rename from src/config.hpp
rename to src/common/config.hpp
index 401e049..e187f5a 100644
--- a/src/config.hpp
+++ b/src/common/config.hpp
@@ -2,6 +2,7 @@
#define __MAJORMINER_CONFIG_HPP_
#define EIGEN_MPL2_ONLY
+#define TBB_PREVIEW_CONCURRENT_LRU_CACHE 1
#define __DEBUG__ 1
diff --git a/src/common/csc_problem.cpp b/src/common/csc_problem.cpp
new file mode 100644
index 0000000..a2c5ff1
--- /dev/null
+++ b/src/common/csc_problem.cpp
@@ -0,0 +1,71 @@
+#include "common/csc_problem.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace majorminer;
+
+adjacency_list_t majorminer::extractSubgraph(const EmbeddingBase& base, fuint32_t sourceNode)
+{
+ adjacency_list_t subgraph{};
+ const auto& targetGraph = *base.getTargetGraph();
+ base.iterateSourceMappingPair(sourceNode,
+ [&subgraph, &targetGraph](fuint32_t targetNodeA, fuint32_t targetNodeB){
+ edge_t uv{targetNodeA, targetNodeB};
+ edge_t vu{targetNodeB, targetNodeA};
+ if (targetGraph.contains(uv) || targetGraph.contains(vu))
+ {
+ subgraph.insert(uv);
+ subgraph.insert(vu);
+ }
+ });
+ return subgraph;
+}
+
+nodeset_t majorminer::getEmbeddedAdjacentSourceVertices(const EmbeddingBase& base, fuint32_t sourceVertex)
+{
+ const auto& mapping = base.getMapping();
+ nodeset_t connections{};
+
+ base.iterateSourceGraphAdjacent(sourceVertex, [&](fuint32_t adjSourceNode){
+ if (mapping.contains(adjSourceNode)) connections.insert(adjSourceNode);
+ });
+ return connections;
+}
+
+bool majorminer::isNodeCrucial(const EmbeddingBase& base, fuint32_t sourceNode, fuint32_t targetNode, fuint32_t conqueror)
+{
+ // 1. Check whether targetNode is crucial due to it being a cut vertex
+ // std::cout << "Checking whether cut vertex " << std::endl;
+ if (isCutVertex(base, sourceNode, targetNode)) return true;
+ // std::cout << "Is no cut vertex" << std::endl;
+ // 2. Check whether targetNode is crucial connections to other super vertices
+ nodeset_t connections = getEmbeddedAdjacentSourceVertices(base, sourceNode);
+ connections.unsafe_erase(conqueror);
+
+ base.iterateSourceMappingAdjacentReverse(sourceNode, targetNode, [&](fuint32_t adjSourceNode){
+ connections.unsafe_erase(adjSourceNode);
+ return connections.empty();
+ });
+ // std::cout << "Connections empty? " << connections.empty() << std::endl;
+ return !connections.empty();
+}
+
+
+bool majorminer::connectsToAdjacentVertices(const EmbeddingManager& base,
+ const nodeset_t& placement, fuint32_t sourceVertex)
+{
+ nodeset_t connections = getEmbeddedAdjacentSourceVertices(base, sourceVertex);
+
+ for (auto target : placement)
+ {
+ base.iterateTargetAdjacentReverseMapping(target,
+ [&connections](fuint32_t sourceAdj){
+ connections.unsafe_erase(sourceAdj);
+ });
+ }
+ return connections.empty();
+}
diff --git a/src/common/csc_problem.hpp b/src/common/csc_problem.hpp
new file mode 100644
index 0000000..b92b17b
--- /dev/null
+++ b/src/common/csc_problem.hpp
@@ -0,0 +1,18 @@
+#ifndef __MAJORMINER_CSC_PROBLEM_HPP_
+#define __MAJORMINER_CSC_PROBLEM_HPP_
+
+#include
+
+namespace majorminer
+{
+ adjacency_list_t extractSubgraph(const EmbeddingBase& base, fuint32_t sourceNode);
+
+ nodeset_t getEmbeddedAdjacentSourceVertices(const EmbeddingBase& base, fuint32_t sourceVertex);
+
+ bool isNodeCrucial(const EmbeddingBase& base, fuint32_t sourceNode, fuint32_t targetNode, fuint32_t conqueror);
+
+ bool connectsToAdjacentVertices(const EmbeddingManager& base, const nodeset_t& placement, fuint32_t sourceVertex);
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/cut_vertex.cpp b/src/common/cut_vertex.cpp
index 684886b..ca2a48d 100644
--- a/src/common/cut_vertex.cpp
+++ b/src/common/cut_vertex.cpp
@@ -1,6 +1,9 @@
#include "cut_vertex.hpp"
+#include
+#include
+
using namespace majorminer;
typedef adjacency_list_t::const_iterator adj_list_const_it;
@@ -9,13 +12,13 @@ typedef std::pair equal_range_t;
struct VertexData
{
VertexData()
- : m_parent((fuint32_t)-1), m_depth(m_parent),
+ : m_parent((vertex_t)-1), m_depth(m_parent),
m_lowest(m_parent), m_recursed(false) {}
- VertexData(fuint32_t parent, fuint32_t depth)
+ VertexData(vertex_t parent, fuint32_t depth)
: m_parent(parent), m_depth(depth),
m_lowest(depth), m_recursed(false) {}
- fuint32_t m_parent;
+ vertex_t m_parent;
fuint32_t m_depth;
fuint32_t m_lowest;
bool m_recursed;
@@ -25,13 +28,12 @@ void majorminer::identifiyCutVertices(nodeset_t& cut, const adjacency_list_t& su
{
if (subgraph.empty()) return;
Stack nodeStack{};
- Vector edgesDfs{};
- UnorderedMap properties{};
+ UnorderedMap properties{};
- fuint32_t rootNode = subgraph.begin()->first;
+ vertex_t rootNode = subgraph.begin()->first;
nodeStack.push(subgraph.equal_range(rootNode));
- properties.insert(std::make_pair(rootNode, VertexData{ (fuint32_t)-1, 0 }));
+ properties.insert(std::make_pair(rootNode, VertexData{ (vertex_t)-1, 0 }));
fuint32_t depth = 1;
fuint32_t rootChildren = 0;
@@ -40,8 +42,8 @@ void majorminer::identifiyCutVertices(nodeset_t& cut, const adjacency_list_t& su
auto& top = nodeStack.top();
if (top.first != top.second)
{
- fuint32_t currentNode = top.first->first;
- fuint32_t nextNode = top.first->second;
+ vertex_t currentNode = top.first->first;
+ vertex_t nextNode = top.first->second;
auto& p = properties[currentNode];
if (p.m_recursed)
{ // take care of last "recursion" (not actually recursing)
@@ -78,11 +80,11 @@ void majorminer::identifiyCutVertices(nodeset_t& cut, const adjacency_list_t& su
// Conduct a depth-first search that does not visit the vertex "node".
// If all nodes were visited, then node is not a cut vertex
-bool majorminer::isCutVertex(const adjacency_list_t& subgraph, fuint32_t node, fuint32_t n)
+bool majorminer::isCutVertex(const adjacency_list_t& subgraph, vertex_t node, fuint32_t n)
{
auto nodeFind = subgraph.find(node);
- if (nodeFind == subgraph.end()) return false;
- fuint32_t rootNode = nodeFind->second;
+ if (nodeFind == subgraph.end()) return true;
+ vertex_t rootNode = nodeFind->second;
if (rootNode == node) throw std::runtime_error("Loop inside subgraph!");
Stack nodeStack{};
@@ -96,7 +98,7 @@ bool majorminer::isCutVertex(const adjacency_list_t& subgraph, fuint32_t node, f
auto& top = nodeStack.top();
if (top.first != top.second)
{
- fuint32_t nextNode = top.first->second;
+ vertex_t nextNode = top.first->second;
top.first++;
if (!visited.contains(nextNode))
{
@@ -107,4 +109,68 @@ bool majorminer::isCutVertex(const adjacency_list_t& subgraph, fuint32_t node, f
else nodeStack.pop();
}
return visited.size() < n;
+}
+
+
+
+bool majorminer::isCutVertex(const EmbeddingBase& base, vertex_t sourceNode, vertex_t targetNode)
+{
+ nodeset_t mapped {};
+ insertMappedTargetNodes(base, mapped, sourceNode);
+ return isCutVertex(base, mapped, targetNode);
+}
+
+bool majorminer::isCutVertex(const EmbeddingBase& base, nodeset_t& mappedNodes, vertex_t targetNode)
+{
+ if (mappedNodes.size() <= 1) return true;
+ mappedNodes.unsafe_erase(targetNode);
+ const auto& targetAdj = base.getTargetAdjGraph();
+ vertex_t adjacentTarget = FUINT32_UNDEF; // cannot use targetNode here
+ auto range = targetAdj.equal_range(targetNode);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ if (mappedNodes.contains(it->second))
+ {
+ adjacentTarget = it->second;
+ break;
+ }
+ }
+ if (!isDefined(adjacentTarget)) return true;
+ mappedNodes.unsafe_erase(adjacentTarget);
+
+ Stack nodeStack{};
+ nodeStack.push(targetAdj.equal_range(adjacentTarget));
+ while(!nodeStack.empty())
+ {
+ auto& top = nodeStack.top();
+ if (top.first == top.second) nodeStack.pop();
+ else if (top.first->second == targetNode) top.first++;
+ else
+ {
+ vertex_t next = top.first->second;
+ top.first++;
+ auto val = mappedNodes.unsafe_extract(next);
+ if (!val.empty())
+ {
+ if (mappedNodes.empty()) return false;
+ nodeStack.push(targetAdj.equal_range(next));
+ }
+ }
+ }
+ return !mappedNodes.empty();
+}
+
+
+bool majorminer::areSetsConnected(const EmbeddingBase& base, const nodeset_t& setA, const nodeset_t& setB)
+{
+ bool connected = false;
+ for (auto target : setA)
+ {
+ base.iterateTargetGraphAdjacentBreak(target, [&](vertex_t adjTarget){
+ if (setB.contains(adjTarget)) connected = true;
+ return connected;
+ });
+ if (connected) return true;
+ }
+ return false;
}
\ No newline at end of file
diff --git a/src/common/cut_vertex.hpp b/src/common/cut_vertex.hpp
index 77344ba..21f3df5 100644
--- a/src/common/cut_vertex.hpp
+++ b/src/common/cut_vertex.hpp
@@ -1,8 +1,7 @@
#ifndef __MAJORMINER_CUT_VERTEX_HPP_
#define __MAJORMINER_CUT_VERTEX_HPP_
-#include "majorminer_types.hpp"
-#include "common/utils.hpp"
+#include
namespace majorminer
{
@@ -11,8 +10,13 @@ namespace majorminer
void identifiyCutVertices(nodeset_t& cut, const adjacency_list_t& subgraph, fuint32_t n);
// check whether node is a cut vertex (needed for validation in FrontierShifting)
- bool isCutVertex(const adjacency_list_t& subgraph, fuint32_t node, fuint32_t n);
+ bool isCutVertex(const adjacency_list_t& subgraph, vertex_t node, fuint32_t n);
+ // check whether targetNode (which is a node sourceNode is mapped to) is a cut vertex
+ bool isCutVertex(const EmbeddingBase& base, vertex_t sourceNode, vertex_t targetNode);
+ bool isCutVertex(const EmbeddingBase& base, nodeset_t& mappedNodes, vertex_t targetNode);
+
+ bool areSetsConnected(const EmbeddingBase& base, const nodeset_t& setA, const nodeset_t& setB);
}
diff --git a/src/common/debug_utils.cpp b/src/common/debug_utils.cpp
new file mode 100644
index 0000000..329c66e
--- /dev/null
+++ b/src/common/debug_utils.cpp
@@ -0,0 +1,60 @@
+#include
+#include
+
+#include
+
+using namespace majorminer;
+
+
+void majorminer::printNodeset(const nodeset_t& nodeset)
+{
+ Vector nodes{};
+ nodes.reserve(nodeset.size());
+ nodes.assign(nodeset.begin(), nodeset.end());
+ std::sort(nodes.begin(), nodes.end());
+
+ std::cout << "{";
+ for (auto node : nodes) std::cout << " " << node;
+ std::cout << " }" << std::endl;
+}
+
+
+void majorminer::printAdjacencyList(const adjacency_list_t& adj)
+{
+ for (const auto& edge : adj)
+ {
+ std::cout << "(" << edge.first << ", " << edge.second << ")" << std::endl;
+ }
+}
+
+void majorminer::printVertexNumberMap(const VertexNumberMap& m)
+{
+ for (const auto& p : m)
+ {
+ std::cout << "(" << p.first << ", " << p.second << ") ";
+ }
+ std::cout << std::endl;
+}
+
+embedding_mapping_t majorminer::getReverseMapping(const embedding_mapping_t& mapping)
+{
+ embedding_mapping_t reverse{};
+ for (const auto& mapped : mapping) reverse.insert(reversePair(mapped));
+ return reverse;
+}
+
+void majorminer::printEmbeddingOverlapStats(const embedding_mapping_t& mapping)
+{
+ VertexNumberMap overlapStat{};
+ embedding_mapping_t reverse = getReverseMapping(mapping);
+ for (const auto& rev : reverse)
+ {
+ if(reverse.count(rev.first) > 1) overlapStat[rev.second]++;
+ }
+ Vector stats{};
+ stats.reserve(overlapStat.size());
+ for (const auto& p : overlapStat) stats.push_back(reversePair(p));
+ std::sort(stats.begin(), stats.end(), PairFirstKeySorter());
+ for (const auto& stat : stats) std::cout << "Source vertex " << stat.second << " is mapped onto " << stat.first << " vertices." << std::endl;
+}
+
diff --git a/src/common/debug_utils.hpp b/src/common/debug_utils.hpp
new file mode 100644
index 0000000..f242b45
--- /dev/null
+++ b/src/common/debug_utils.hpp
@@ -0,0 +1,22 @@
+#ifndef __MAJORMINER_DEBUG_UTILS_HPP_
+#define __MAJORMINER_DEBUG_UTILS_HPP_
+
+#include
+
+namespace majorminer
+{
+
+ #define TEST_OUTPUT(content) std::cout << #content << std::endl;
+
+ void printAdjacencyList(const adjacency_list_t& adj);
+
+ void printNodeset(const nodeset_t& nodeset);
+
+ void printVertexNumberMap(const VertexNumberMap& m);
+
+ embedding_mapping_t getReverseMapping(const embedding_mapping_t& mapping);
+
+ void printEmbeddingOverlapStats(const embedding_mapping_t& mapping);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/common/embedding_analyzer.hpp b/src/common/embedding_analyzer.hpp
index fe54fb3..58319d7 100644
--- a/src/common/embedding_analyzer.hpp
+++ b/src/common/embedding_analyzer.hpp
@@ -1,8 +1,6 @@
#ifndef __MAJORMINER_EMBEDDING_ANALYZER_HPP_
#define __MAJORMINER_EMBEDDING_ANALYZER_HPP_
-#include
-
#include "majorminer_types.hpp"
namespace majorminer
diff --git a/src/common/embedding_base.hpp b/src/common/embedding_base.hpp
new file mode 100644
index 0000000..a7b6c0d
--- /dev/null
+++ b/src/common/embedding_base.hpp
@@ -0,0 +1,197 @@
+#ifndef __MAJORMINER_EMBEDDING_BASE_HPP_
+#define __MAJORMINER_EMBEDDING_BASE_HPP_
+
+#include
+
+namespace majorminer
+{
+
+ class EmbeddingBase
+ {
+ public:
+ virtual ~EmbeddingBase(){}
+
+ // getters
+ virtual const graph_t* getSourceGraph() const = 0;
+ virtual const graph_t* getTargetGraph() const = 0;
+ virtual const adjacency_list_t& getSourceAdjGraph() const = 0;
+ virtual const adjacency_list_t& getTargetAdjGraph() const = 0;
+ virtual const embedding_mapping_t& getMapping() const = 0;
+ virtual const embedding_mapping_t& getReverseMapping() const = 0;
+ virtual const nodeset_t& getNodesOccupied() const = 0;
+ virtual const nodeset_t& getRemainingTargetNodes() const = 0;
+
+
+ bool isTargetNodeOccupied(vertex_t targetNode) const { return getRemainingTargetNodes().contains(targetNode); }
+ virtual int numberFreeNeighborsNeeded(vertex_t sourceNode) const = 0;
+
+ // Iteration methods
+ public:
+
+ // For a given sourceNode, iterate over all target nodes sourceNode is mapped onto.
+ // For these target nodes, iterate over all their neighbors
+ // but skip a neighbor if skipOccupied && isOccupied(neighbor)
+ // Callback functor should take as parameters
+ // 1. fuint32_t target neighbor
+ // 2. fuint32_t target sourceNode is mapped onto
+ template
+ void iterateSourceMappingAdjacent(vertex_t sourceNode, Functor func) const
+ {
+ auto embeddedPathIt = getMapping().equal_range(sourceNode);
+ const auto& target = getTargetAdjGraph();
+ const auto& remaining = getRemainingTargetNodes();
+
+ for (auto targetNode = embeddedPathIt.first; targetNode != embeddedPathIt.second; ++targetNode)
+ {
+ // find nodes that are adjacent to targetNode (in the targetGraph)
+ auto targetGraphAdjacentIt = target.equal_range(targetNode->second);
+ for (auto targetAdjacent = targetGraphAdjacentIt.first; targetAdjacent != targetGraphAdjacentIt.second; ++targetAdjacent)
+ {
+ if (skipOccupied && !remaining.contains(targetAdjacent->second)) continue;
+ if (func(targetAdjacent->second, targetNode->second)) return;
+ }
+ }
+ }
+
+ template
+ void iterateReverseMapping(vertex_t mappedTargetNode, Functor func) const
+ {
+ auto revRange = getReverseMapping().equal_range(mappedTargetNode);
+ for (auto revIt = revRange.first; revIt != revRange.second; ++revIt)
+ {
+ func(revIt->second);
+ }
+ }
+
+ // Iterate for a sourceNode over all target nodes source Node is mapped to.
+ // For these target nodes iterate over their adjacent nodes and for the adjacent nodes
+ // iterate over their reverse mapping. Awful everything.
+ template
+ void iterateSourceMappingAdjacentReverse(vertex_t sourceNode, vertex_t skipTarget, Functor func) const
+ {
+ auto embeddedPathIt = getMapping().equal_range(sourceNode);
+ const auto& target = getTargetAdjGraph();
+ const auto& reverseMapping = getReverseMapping();
+
+ for (auto mapIt = embeddedPathIt.first; mapIt != embeddedPathIt.second; ++mapIt)
+ {
+ if (mapIt->second == skipTarget) continue;
+ auto targetGraphAdjacentIt = target.equal_range(mapIt->second);
+ for (auto targetAdjacent = targetGraphAdjacentIt.first; targetAdjacent != targetGraphAdjacentIt.second; ++targetAdjacent)
+ {
+ auto revRange = reverseMapping.equal_range(targetAdjacent->second);
+ for (auto revIt = revRange.first; revIt != revRange.second; ++revIt)
+ {
+ if (revIt->second != sourceNode && func(revIt->second)) return;
+ }
+ }
+ }
+ }
+
+ template
+ void iterateTargetGraphAdjacent(vertex_t targetNode, Functor func) const
+ {
+ auto adjRange = getTargetAdjGraph().equal_range(targetNode);
+ for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
+ {
+ func(adj->second);
+ }
+ }
+
+ template
+ void iterateSourceGraphAdjacent(vertex_t sourceNode, Functor func) const
+ {
+ auto adjRange = getSourceAdjGraph().equal_range(sourceNode);
+ for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
+ {
+ func(adj->second);
+ }
+ }
+
+ template
+ void iterateSourceGraphAdjacentBreak(vertex_t sourceNode, Functor func) const
+ {
+ auto adjRange = getSourceAdjGraph().equal_range(sourceNode);
+ for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
+ {
+ if (func(adj->second)) return;
+ }
+ }
+
+ template
+ void iterateTargetGraphAdjacentBreak(vertex_t targetNode, Functor func) const
+ {
+ auto adjRange = getTargetAdjGraph().equal_range(targetNode);
+ for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
+ {
+ if (func(adj->second)) return;
+ }
+ }
+
+ template
+ void iterateTargetAdjacentReverseMapping(vertex_t target, Functor func) const
+ {
+ const auto& targetGraph = getTargetAdjGraph();
+ const auto& reverse = getReverseMapping();
+ auto adjacentRange = targetGraph.equal_range(target);
+ for (auto adjIt = adjacentRange.first; adjIt != adjacentRange.second; ++adjIt)
+ {
+ auto revMappedRange = reverse.equal_range(adjIt->second);
+ for (auto revIt = revMappedRange.first; revIt != revMappedRange.second; ++revIt)
+ {
+ func(revIt->second);
+ }
+ }
+ }
+
+
+ /// For a given source node, iterates over every pair of two target nodes the source node
+ /// is mapped to and invokes the functor func using this pair of target nodes.
+ template
+ void iterateSourceMappingPair(vertex_t sourceVertex, Functor func) const
+ {
+ const auto& mapping = getMapping();
+ auto mappedRange = mapping.equal_range(sourceVertex);
+ for (auto mapped1It = mappedRange.first; mapped1It != mappedRange.second; ++mapped1It)
+ {
+ auto mapped2It = mapped1It;
+ mapped2It++;
+
+ for (; mapped2It != mappedRange.second; ++mapped2It)
+ {
+ func(mapped1It->second, mapped2It->second);
+ }
+ }
+ }
+
+ template
+ void iterateSourceMapping(vertex_t sourceVertex, Functor func) const
+ {
+ const auto& mapping = getMapping();
+ auto mappingRange = mapping.equal_range(sourceVertex);
+ for (auto it = mappingRange.first; it != mappingRange.second; ++it)
+ {
+ func(it->second);
+ }
+ }
+
+ template
+ void iterateFreeTargetAdjacent(vertex_t targetVertex, Functor func) const
+ {
+ const auto& remaining = getRemainingTargetNodes();
+ const auto& targetGraph = getTargetAdjGraph();
+ auto range = targetGraph.equal_range(targetVertex);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ if (remaining.contains(it->second)) func(it->second);
+ }
+ }
+ };
+
+
+}
+
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/embedding_manager.cpp b/src/common/embedding_manager.cpp
new file mode 100644
index 0000000..7b98063
--- /dev/null
+++ b/src/common/embedding_manager.cpp
@@ -0,0 +1,219 @@
+#include "common/embedding_manager.hpp"
+
+#include
+#include
+
+#define CACHE_CAPACITY 128
+
+using namespace majorminer;
+
+namespace
+{
+ ShiftingCandidates getEmptyCandidate()
+ {
+ return ShiftingCandidates{0, std::shared_ptr() };
+ }
+}
+
+void EmbeddingManager::mapNode(fuint32_t node, fuint32_t targetNode)
+{
+ if (!m_changesToPropagate.empty()) synchronize();
+ m_lastNode = node;
+ DEBUG(std::cout << node << " -> " << targetNode << std::endl;)
+
+ m_nodesOccupied.insert(targetNode);
+ m_mapping.insert(std::make_pair(node, targetNode));
+ m_reverseMapping.insert(std::make_pair(targetNode, node));
+ m_targetNodesRemaining.unsafe_extract(targetNode);
+ m_state.mapNode(node, targetNode);
+}
+
+void EmbeddingManager::mapNode(fuint32_t node, const nodeset_t& targetNodes)
+{
+ if (!m_changesToPropagate.empty()) synchronize();
+ m_lastNode = node;
+ DEBUG(OUT_S << node << " -> {";)
+ for(auto targetNode : targetNodes)
+ {
+ DEBUG(OUT_S << " " << targetNode;)
+ m_nodesOccupied.insert(targetNode);
+ m_mapping.insert(std::make_pair(node, targetNode));
+ m_reverseMapping.insert(std::make_pair(targetNode, node));
+ m_targetNodesRemaining.unsafe_extract(targetNode);
+
+ }
+ DEBUG(OUT_S << " }" << std::endl;)
+ m_state.mapNode(node, targetNodes);
+}
+#undef ADJUST
+
+void EmbeddingManager::unmapNode(vertex_t sourceVertex)
+{
+ auto range = m_mapping.equal_range(sourceVertex);
+ for (auto mappedIt = range.first; mappedIt != range.second; ++mappedIt)
+ {
+ eraseSinglePair(m_reverseMapping, mappedIt->second, mappedIt->first);
+ }
+ m_mapping.unsafe_erase(sourceVertex);
+ m_state.unmapNode(sourceVertex);
+}
+
+EmbeddingManager::EmbeddingManager(EmbeddingSuite& suite, EmbeddingState& state)
+ : m_suite(suite), m_state(state),
+ m_candidateCache([](fuint32_t) {return getEmptyCandidate(); }, CACHE_CAPACITY),
+ m_nbCommitsRemaining(0), m_time(1)
+{
+ const auto& targetNodes = m_state.getRemainingTargetNodes();
+ m_targetNodesRemaining.insert(targetNodes.begin(), targetNodes.end());
+}
+
+
+void EmbeddingManager::setFreeNeighbors(fuint32_t node, fuint32_t nbNeighbors)
+{
+ m_changesToPropagate.push(EmbeddingChange{ChangeType::FREE_NEIGHBORS, node, nbNeighbors});
+ m_sourceFreeNeighbors[node] = nbNeighbors;
+}
+
+void EmbeddingManager::deleteMappingPair(fuint32_t source, fuint32_t target)
+{
+ m_changesToPropagate.push(EmbeddingChange{ChangeType::DEL_MAPPING, source, target});
+ eraseSinglePair(m_mapping, source, target);
+ eraseSinglePair(m_reverseMapping, target, source);
+}
+
+void EmbeddingManager::insertMappingPair(fuint32_t source, fuint32_t target)
+{
+ m_changesToPropagate.push(EmbeddingChange{ChangeType::INS_MAPPING, source, target});
+ m_mapping.insert(std::make_pair(source, target));
+ m_reverseMapping.insert(std::make_pair(target, source));
+}
+
+void EmbeddingManager::occupyNode(fuint32_t target)
+{
+ m_changesToPropagate.push(EmbeddingChange{ChangeType::OCCUPY_NODE, target});
+ m_nodesOccupied.insert(target);
+ m_targetNodesRemaining.unsafe_erase(target);
+}
+
+void EmbeddingManager::freeNode(fuint32_t target)
+{
+ m_changesToPropagate.push(EmbeddingChange{ChangeType::FREE_NODE, target});
+ m_nodesOccupied.unsafe_erase(target);
+ m_targetNodesRemaining.insert(target);
+}
+
+int EmbeddingManager::numberFreeNeighborsNeeded(fuint32_t sourceNode) const
+{ // TODO: rework and correct?!
+ auto it = m_sourceFreeNeighbors.find(sourceNode);
+ return 2 * m_state.getSourceNeededNeighbors()[sourceNode].load()
+ - (it == m_sourceFreeNeighbors.end() ? 0 : std::max(it->second.load(), 0));
+}
+
+void EmbeddingManager::commit()
+{
+ m_changesToPropagate.push(EmbeddingChange{});
+ m_nbCommitsRemaining++;
+}
+
+void EmbeddingManager::synchronize()
+{
+ EmbeddingChange change{};
+ auto& mapping = m_state.getMapping();
+ auto& revMapping = m_state.getReverseMapping();
+ auto& sourceFreeNeighbors = m_state.getSourceFreeNeighbors();
+ auto& nodesOccupied = m_state.getNodesOccupied();
+ auto& targetNodesRemaining = m_state.getRemainingTargetNodes();
+ while(!m_changesToPropagate.empty() && m_nbCommitsRemaining > 0)
+ {
+ bool success = m_changesToPropagate.try_pop(change);
+ if (!success) break;
+ switch(change.m_type)
+ {
+ case ChangeType::DEL_MAPPING:
+ {
+ eraseSinglePair(mapping, change.m_a, change.m_b);
+ eraseSinglePair(revMapping, change.m_b, change.m_a);
+ m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
+ break;
+ }
+ case ChangeType::INS_MAPPING:
+ {
+ mapping.insert(std::make_pair(change.m_a, change.m_b));
+ revMapping.insert(std::make_pair(change.m_b, change.m_a));
+ m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
+ break;
+ }
+ case ChangeType::FREE_NEIGHBORS:
+ {
+ sourceFreeNeighbors[change.m_a] = change.m_b;
+ m_changeHistory[change.m_a].m_timestampEdgeChanged = m_time.load();
+ break;
+ }
+ case ChangeType::OCCUPY_NODE:
+ {
+ targetNodesRemaining.unsafe_erase(change.m_a);
+ nodesOccupied.insert(change.m_a);
+ m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
+ break;
+ }
+ case ChangeType::FREE_NODE:
+ {
+ targetNodesRemaining.insert(change.m_a);
+ nodesOccupied.unsafe_erase(change.m_a);
+ m_changeHistory[change.m_a].m_timestampNodeChanged = m_time.load();
+ break;
+ }
+ case ChangeType::COMMIT:
+ {
+ m_nbCommitsRemaining--;
+ break;
+ }
+ }
+ }
+}
+
+void EmbeddingManager::clear()
+{
+ for (auto& entry : m_changeHistory)
+ {
+ entry.second.clear();
+ }
+ m_time = 0;
+ m_changesToPropagate.clear();
+ m_nbCommitsRemaining = 0;
+}
+
+ShiftingCandidates EmbeddingManager::getCandidatesFor(fuint32_t conquerorNode)
+{
+ auto handle = m_candidateCache[conquerorNode];
+ if (handle) return handle.value();
+ else return getEmptyCandidate();
+}
+
+
+ShiftingCandidates EmbeddingManager::setCandidatesFor(fuint32_t conquerorNode, nodepairset_t& candidates)
+{
+ fuint32_t size = candidates.size();
+ ShiftingCandidates element = std::make_pair(size, majorminer::make_shared_array(size));
+ m_random.shuffle(element.second.get(), size);
+ fuint32_pair_t* writePtr = element.second.get();
+ for (const auto& candidate : candidates) *writePtr++ = candidate;
+ m_candidateCache[conquerorNode].value() = element;
+ return element;
+}
+
+EmbeddingVisualizer* EmbeddingManager::getVisualizer()
+{
+ return m_state.getVisualizer();
+}
+
+const graph_t* EmbeddingManager::getSourceGraph() const { return m_state.getSourceGraph(); }
+const graph_t* EmbeddingManager::getTargetGraph() const { return m_state.getTargetGraph(); }
+const adjacency_list_t& EmbeddingManager::getSourceAdjGraph() const { return m_state.getSourceAdjGraph(); }
+const adjacency_list_t& EmbeddingManager::getTargetAdjGraph() const { return m_state.getTargetAdjGraph(); }
+const embedding_mapping_t& EmbeddingManager::getMapping() const { return m_mapping; }
+const embedding_mapping_t& EmbeddingManager::getReverseMapping() const { return m_reverseMapping; }
+const nodeset_t& EmbeddingManager::getNodesOccupied() const { return m_nodesOccupied; }
+const nodeset_t& EmbeddingManager::getRemainingTargetNodes() const { return m_targetNodesRemaining; }
+
+
diff --git a/src/common/embedding_manager.hpp b/src/common/embedding_manager.hpp
new file mode 100644
index 0000000..97ca21e
--- /dev/null
+++ b/src/common/embedding_manager.hpp
@@ -0,0 +1,123 @@
+#ifndef __MAJORMINER_EMBEDDING_MANAGER_HPP
+#define __MAJORMINER_EMBEDDING_MANAGER_HPP
+
+#include
+#include
+#include
+
+namespace majorminer
+{
+ enum ChangeType
+ {
+ DEL_MAPPING,
+ INS_MAPPING,
+ FREE_NEIGHBORS,
+ OCCUPY_NODE,
+ COMMIT,
+ FREE_NODE
+ };
+
+ struct EmbeddingChange
+ {
+ EmbeddingChange()
+ : m_type(ChangeType::COMMIT), m_a((fuint32_t)-1),
+ m_b((fuint32_t)-1){}
+ EmbeddingChange(ChangeType t, fuint32_t a)
+ : m_type(t), m_a(a), m_b((fuint32_t)-1) {}
+ EmbeddingChange(ChangeType t, fuint32_t a, fuint32_t b)
+ : m_type(t), m_a(a), m_b(b) {}
+
+ ChangeType m_type;
+ fuint32_t m_a;
+ fuint32_t m_b;
+ };
+
+ struct NodeAffected
+ {
+ NodeAffected()
+ : m_timestampNodeChanged(0),
+ m_timestampEdgeChanged(0) {}
+ void clear()
+ {
+ m_timestampNodeChanged = 0;
+ m_timestampEdgeChanged = 0;
+ }
+
+ fuint32_t m_timestampNodeChanged;
+ fuint32_t m_timestampEdgeChanged;
+ };
+
+ class EmbeddingManager : public EmbeddingBase
+ {
+ friend SuperVertexPlacer;
+ friend NetworkSimplexWrapper;
+ friend MutationManager;
+ public:
+ EmbeddingManager(EmbeddingSuite& suite, EmbeddingState& state);
+ void setFreeNeighbors(vertex_t node, fuint32_t nbNeighbors);
+ void deleteMappingPair(vertex_t source, vertex_t target);
+ void insertMappingPair(vertex_t source, vertex_t target);
+ void occupyNode(vertex_t target);
+ void freeNode(vertex_t target);
+ void synchronize();
+ void commit();
+ fuint32_t getTimestamp() { return m_time++; }
+ int numberFreeNeighborsNeeded(vertex_t sourceNode) const override;
+ const NodeAffected& getHistory(vertex_t node) { return m_changeHistory[node]; }
+
+ const UnorderedMap>& getFreeNeighborMap() const { return m_sourceFreeNeighbors; }
+
+ fuint32_t getLastNode() const { return m_lastNode; }
+
+ ShiftingCandidates getCandidatesFor(vertex_t conquerorNode);
+ ShiftingCandidates setCandidatesFor(vertex_t conquerorNode, nodepairset_t& candidates);
+
+ RandomGen& getRandomGen() { return m_random; }
+
+ EmbeddingVisualizer* getVisualizer();
+
+ public:
+ const graph_t* getSourceGraph() const override;
+ const graph_t* getTargetGraph() const override;
+ const adjacency_list_t& getSourceAdjGraph() const override;
+ const adjacency_list_t& getTargetAdjGraph() const override;
+ const embedding_mapping_t& getMapping() const override;
+ const embedding_mapping_t& getReverseMapping() const override;
+ const nodeset_t& getNodesOccupied() const override;
+ const nodeset_t& getRemainingTargetNodes() const override;
+
+
+ private:
+ void unmapNode(vertex_t sourceVertex);
+ void mapNode(vertex_t source, vertex_t target);
+ void mapNode(vertex_t source, const nodeset_t& targets);
+ void clear();
+
+ private:
+ EmbeddingSuite& m_suite;
+ EmbeddingState& m_state;
+ CandidateCache m_candidateCache;
+ RandomGen m_random;
+
+ embedding_mapping_t m_mapping;
+ embedding_mapping_t m_reverseMapping;
+ nodeset_t m_nodesOccupied;
+ nodeset_t m_targetNodesRemaining;
+ UnorderedMap> m_sourceFreeNeighbors;
+ Queue m_changesToPropagate;
+ std::atomic m_nbCommitsRemaining;
+
+ UnorderedMap m_changeHistory;
+
+ std::atomic m_time;
+
+ fuint32_t m_lastNode = (fuint32_t)-1;
+ };
+
+
+
+}
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/embedding_state.cpp b/src/common/embedding_state.cpp
new file mode 100644
index 0000000..e1c28c5
--- /dev/null
+++ b/src/common/embedding_state.cpp
@@ -0,0 +1,116 @@
+#include "embedding_state.hpp"
+
+#include "common/utils.hpp"
+
+using namespace majorminer;
+
+EmbeddingState::EmbeddingState(const graph_t& sourceGraph, const graph_t& targetGraph, EmbeddingVisualizer* vis)
+ : m_sourceGraph(&sourceGraph), m_targetGraph(&targetGraph), m_visualizer(vis)
+{
+ initialize();
+}
+
+void EmbeddingState::initialize()
+{
+ convertToAdjacencyList(m_source, *m_sourceGraph);
+ convertToAdjacencyList(m_target, *m_targetGraph);
+ for (const auto& arc : *m_targetGraph)
+ {
+ m_targetNodesRemaining.insert(arc.first);
+ m_targetNodesRemaining.insert(arc.second);
+ }
+ for (const auto& arc : *m_sourceGraph)
+ {
+ m_nodesRemaining[arc.first] = 0;
+ m_nodesRemaining[arc.second] = 0;
+ m_sourceNeededNeighbors[arc.first]++;
+ m_sourceNeededNeighbors[arc.second]++;
+ }
+ m_numberSourceVertices = m_nodesRemaining.size();
+}
+
+fuint32_t EmbeddingState::getTrivialNode()
+{ // TODO: assert
+ auto node = *m_nodesRemaining.begin();
+ m_nodesRemaining.unsafe_erase(m_nodesRemaining.begin());
+ return node.first;
+}
+
+bool EmbeddingState::removeRemainingNode(fuint32_t node)
+{
+ if (!m_nodesRemaining.contains(node)) return false;
+ m_nodesRemaining.unsafe_erase(node);
+ return true;
+}
+
+void EmbeddingState::unmapNode(vertex_t sourceVertex)
+{
+ auto range = m_mapping.equal_range(sourceVertex);
+ for (auto mappedIt = range.first; mappedIt != range.second; ++mappedIt)
+ {
+ eraseSinglePair(m_reverseMapping, mappedIt->second, mappedIt->first);
+ }
+ m_mapping.unsafe_erase(sourceVertex);
+}
+
+void EmbeddingState::updateNeededNeighbors(fuint32_t node)
+{
+ fuint32_t nbNodes = 0;
+ iterateSourceGraphAdjacent(node, [&, this](fuint32_t adjacentSource){
+ if (isNodeMapped(adjacentSource))
+ {
+ nbNodes++; m_sourceNeededNeighbors[adjacentSource]--;
+ }
+ });
+ m_sourceNeededNeighbors[node] -= nbNodes;
+}
+
+
+void EmbeddingState::updateConnections(fuint32_t node, PrioNodeQueue& nodesToProcess)
+{
+ iterateSourceGraphAdjacent(node, [&](fuint32_t adjacent){
+ auto findIt = m_nodesRemaining.find(adjacent);
+ if (findIt != m_nodesRemaining.end())
+ {
+ findIt->second += 1; // one of its neighbors is now embedded
+ nodesToProcess.push(PrioNode{findIt->first, findIt->second});
+ }
+ });
+}
+
+int EmbeddingState::numberFreeNeighborsNeeded(fuint32_t sourceNode) const
+{ // TODO: rework
+ // std::cout << "Source node " << sourceNode << " needs " << m_sourceNeededNeighbors[sourceNode].load() << " neighbors and has " << m_sourceFreeNeighbors[sourceNode].load() << std::endl;
+ auto it = m_sourceNeededNeighbors.find(sourceNode);
+ return 2 * (it == m_sourceNeededNeighbors.end() ? 0 : it->second.load())
+ - std::max(getSourceNbFreeNeighbors(sourceNode), 0);
+}
+
+int EmbeddingState::getSourceNbFreeNeighbors(fuint32_t sourceNode) const
+{
+ auto it = m_sourceFreeNeighbors.find(sourceNode);
+ return it == m_sourceFreeNeighbors.end() ? 0 : it->second.load();
+}
+
+
+void EmbeddingState::mapNode(fuint32_t source, fuint32_t targetNode)
+{
+ m_nodesOccupied.insert(targetNode);
+ m_mapping.insert(std::make_pair(source, targetNode));
+ m_reverseMapping.insert(std::make_pair(targetNode, source));
+ m_targetNodesRemaining.unsafe_extract(targetNode);
+ removeRemainingNode(source);
+}
+
+void EmbeddingState::mapNode(fuint32_t source, const nodeset_t& targets)
+{
+ for (auto targetNode : targets)
+ {
+ m_nodesOccupied.insert(targetNode);
+ m_mapping.insert(std::make_pair(source, targetNode));
+ m_reverseMapping.insert(std::make_pair(targetNode, source));
+ m_targetNodesRemaining.unsafe_extract(targetNode);
+ }
+ removeRemainingNode(source);
+}
+
diff --git a/src/common/embedding_state.hpp b/src/common/embedding_state.hpp
new file mode 100644
index 0000000..03b14a8
--- /dev/null
+++ b/src/common/embedding_state.hpp
@@ -0,0 +1,97 @@
+#ifndef __MAJORMINER_EMBEDDING_STATE_HPP_
+#define __MAJORMINER_EMBEDDING_STATE_HPP_
+
+#include
+#include
+#include
+#include
+
+namespace majorminer
+{
+
+ class EmbeddingState : public EmbeddingBase
+ {
+ friend EmbeddingManager;
+ public:
+ EmbeddingState(const graph_t& sourceGraph, const graph_t& targetGraph, EmbeddingVisualizer* vis);
+
+ void mapNode(fuint32_t node, fuint32_t targetNode);
+ void mapNode(fuint32_t source, const nodeset_t& targets);
+ void updateNeededNeighbors(fuint32_t node);
+ void updateConnections(fuint32_t node, PrioNodeQueue& nodesToProcess);
+ int numberFreeNeighborsNeeded(fuint32_t sourceNode) const;
+ fuint32_t getTrivialNode();
+
+ bool removeRemainingNode(fuint32_t node);
+ bool isNodeMapped(fuint32_t sourceNode) const { return !m_nodesRemaining.contains(sourceNode); }
+
+ bool isNodeOccupied(fuint32_t node) const { return m_nodesOccupied.contains(node); }
+
+ fuint32_t getSuperVertexSize(fuint32_t sourceNode) const { return m_mapping.count(sourceNode); }
+
+ int getSourceNbFreeNeighbors(fuint32_t sourceNode) const;
+
+ ThreadManager& getThreadManager() { return m_threadManager; }
+ void setLMRPSubgraphGenerator(LMRPSubgraph* gen) { m_lmrpGen = gen; }
+
+ public: // getter
+ const graph_t* getSourceGraph() const override { return m_sourceGraph; }
+ const graph_t* getTargetGraph() const override { return m_targetGraph; }
+ const adjacency_list_t& getSourceAdjGraph() const override { return m_source; }
+ const adjacency_list_t& getTargetAdjGraph() const override { return m_target; }
+ const embedding_mapping_t& getMapping() const override { return m_mapping; }
+ const embedding_mapping_t& getReverseMapping() const override { return m_reverseMapping; }
+ const nodeset_t& getNodesOccupied() const override { return m_nodesOccupied; }
+ const nodeset_t& getRemainingTargetNodes() const override { return m_targetNodesRemaining; }
+
+
+ embedding_mapping_t& getMapping() { return m_mapping; }
+ embedding_mapping_t& getReverseMapping() { return m_reverseMapping; }
+ nodeset_t& getNodesOccupied() { return m_nodesOccupied; }
+ nodeset_t& getRemainingTargetNodes() { return m_targetNodesRemaining; }
+ const UnorderedMap& getRemainingNodes() const { return m_nodesRemaining; }
+ UnorderedMap& getRemainingNodes() { return m_nodesRemaining; }
+
+ EmbeddingVisualizer* getVisualizer() { return m_visualizer; }
+ bool hasVisualizer() const { return m_visualizer != nullptr; }
+
+ UnorderedMap>& getSourceFreeNeighbors() { return m_sourceFreeNeighbors; }
+ UnorderedMap>& getSourceNeededNeighbors() { return m_sourceNeededNeighbors; }
+
+ fuint32_t getNumberSourceVertices() const { return m_numberSourceVertices; }
+
+ LMRPSubgraph* getSubgraphGen() { return m_lmrpGen; }
+
+ private:
+ void initialize();
+ void unmapNode(vertex_t sourceVertex);
+
+ private:
+ const graph_t* m_sourceGraph;
+ const graph_t* m_targetGraph;
+ adjacency_list_t m_source;
+ adjacency_list_t m_target;
+
+ embedding_mapping_t m_mapping;
+ embedding_mapping_t m_reverseMapping;
+ nodeset_t m_nodesOccupied;
+ nodeset_t m_targetNodesRemaining;
+
+ UnorderedMap m_nodesRemaining;
+ UnorderedMap> m_sourceNeededNeighbors;
+ UnorderedMap> m_sourceFreeNeighbors;
+ nodeset_t m_sourceNodesAffected;
+ fuint32_t m_numberSourceVertices;
+
+ EmbeddingVisualizer* m_visualizer;
+
+ LMRPSubgraph* m_lmrpGen;
+
+ ThreadManager m_threadManager;
+ };
+
+}
+
+
+
+#endif
diff --git a/src/common/embedding_validator.cpp b/src/common/embedding_validator.cpp
index d8f6092..fd502bf 100644
--- a/src/common/embedding_validator.cpp
+++ b/src/common/embedding_validator.cpp
@@ -1,33 +1,45 @@
#include "embedding_validator.hpp"
+#include
+#include
+
using namespace majorminer;
bool EmbeddingValidator::isDisjoint() const
{
UnorderedSet nodesOccupied{};
- for (const auto& mapped : m_embedding)
+ const auto& embedding = m_state.getMapping();
+ for (const auto& mapped : embedding)
{
- if (nodesOccupied.contains(mapped.second)) return false;
+ if (nodesOccupied.contains(mapped.second))
+ {
+ DEBUG(OUT_S << "Not an injective mapping." << std::endl;)
+ DEBUG(printOverlappings();)
+ return false;
+ }
nodesOccupied.insert(mapped.second);
}
return true;
}
+void EmbeddingValidator::printOverlappings() const
+{
+ fuint32_pair_t stats = calculateOverlappingStats(m_state);
+ std::cout << "Overlapping statistics:" << std::endl
+ << "Distinct overlaps: " << stats.first << std::endl
+ << "Total overlapping: " << stats.second << std::endl;
+}
bool EmbeddingValidator::nodesConnected() const
{
+ const auto& embedding = m_state.getMapping();
+ const auto& sourceGraph = *m_state.getSourceGraph();
UnorderedMultiMap adjacencies{};
- for (const auto& e : m_source)
+ for (const auto& e : sourceGraph)
{
adjacencies.insert(orderedPair(e));
}
- UnorderedMultiMap reverseMapping{};
- for (const auto& mapped : m_embedding)
- {
- reverseMapping.insert(std::make_pair(mapped.second, mapped.first));
- }
-
UnorderedMap> adjacentNodes{};
auto groupIt = adjacencies.begin();
@@ -39,36 +51,28 @@ bool EmbeddingValidator::nodesConnected() const
{
adjacentNodes.insert(std::make_pair(it->second, false));
}
- auto mappedRange = m_embedding.equal_range(groupIt->first);
+ auto mappedRange = embedding.equal_range(groupIt->first);
// for each node in adjacentNodes search for adjacency to mappedNodes
tbb::parallel_for_each(mappedRange.first, mappedRange.second,
- [&adjacentNodes, &reverseMapping, this](fuint32_pair_t targetNodeP) {
- auto targetNodeMapped = reverseMapping.equal_range(targetNodeP.second);
- for (auto it = targetNodeMapped.first; it != targetNodeMapped.second; ++it)
- {
- if (adjacentNodes.contains(it->second))
- {
- adjacentNodes[it->second] = true;
- }
- }
- auto adjacentIt = this->m_target.equal_range(targetNodeP.second);
- for (auto it = adjacentIt.first; it != adjacentIt.second; ++it)
- {
- auto revMappedIt = reverseMapping.equal_range(it->second);
- for (auto revIt = revMappedIt.first; revIt != revMappedIt.second; ++revIt)
- {
- if (adjacentNodes.contains(revIt->second))
- {
- adjacentNodes[revIt->second] = true;
- }
- }
- }
+ [&](fuint32_pair_t targetNodeP) {
+ m_state.iterateReverseMapping(targetNodeP.second, [&](fuint32_t reverse){
+ if (adjacentNodes.contains(reverse)) adjacentNodes[reverse] = true;
+ });
+
+ m_state.iterateTargetAdjacentReverseMapping(targetNodeP.second, [&](fuint32_t revSourceNode){
+ if (adjacentNodes.contains(revSourceNode)) adjacentNodes[revSourceNode] = true;
+ });
});
for (const auto& adjNode : adjacentNodes)
{
- if (!adjNode.second) return false;
+ if (!adjNode.second)
+ {
+ DEBUG(OUT_S << "Not all edges embedded! Node " << adjNode.first << " is missing at least one edge." << std::endl;)
+ DEBUG(printMissingEdges(adjNode.first));
+ return false;
+ }
}
groupIt = adjRange.second;
}
@@ -76,3 +80,24 @@ bool EmbeddingValidator::nodesConnected() const
return true;
}
+
+void EmbeddingValidator::printMissingEdges(fuint32_t node) const
+{
+ nodeset_t missingAdjacent{};
+
+ m_state.iterateSourceGraphAdjacent(node, [&missingAdjacent](fuint32_t adjacentSource)
+ { missingAdjacent.insert(adjacentSource); });
+
+ if (missingAdjacent.empty()) return;
+
+ m_state.iterateSourceMappingAdjacent(node, [&](fuint32_t adjacent, fuint32_t){
+ m_state.iterateReverseMapping(adjacent, [&](fuint32_t reverse){
+ missingAdjacent.unsafe_erase(reverse);
+ });
+ return false;
+ });
+
+ OUT_S << "Node " << node << " is missing edges to nodes { ";
+ for (auto missing : missingAdjacent) OUT_S << missing << " ";
+ OUT_S << "}" << std::endl;
+}
diff --git a/src/common/embedding_validator.hpp b/src/common/embedding_validator.hpp
index 3e89fe2..5e58d0e 100644
--- a/src/common/embedding_validator.hpp
+++ b/src/common/embedding_validator.hpp
@@ -2,7 +2,6 @@
#define __MAJORMINER_EMBEDDING_VALIDATOR_HPP_
#include "majorminer_types.hpp"
-#include "utils.hpp"
namespace majorminer
{
@@ -10,18 +9,19 @@ namespace majorminer
class EmbeddingValidator
{
public:
- EmbeddingValidator(const embedding_mapping_t& embedding,
- const graph_t& source, const adjacency_list_t& target)
- : m_embedding(embedding), m_source(source), m_target(target){}
+ EmbeddingValidator(const EmbeddingState& state)
+ : m_state(state) {}
bool isDisjoint() const;
bool nodesConnected() const;
bool isValid() const { return isDisjoint() && nodesConnected(); }
private:
- const embedding_mapping_t& m_embedding;
- const graph_t& m_source;
- const adjacency_list_t& m_target;
+ void printMissingEdges(vertex_t node) const;
+ void printOverlappings() const;
+
+ private:
+ const EmbeddingState& m_state;
};
}
diff --git a/src/common/embedding_visualizer.cpp b/src/common/embedding_visualizer.cpp
index f631457..464e87e 100644
--- a/src/common/embedding_visualizer.cpp
+++ b/src/common/embedding_visualizer.cpp
@@ -1,5 +1,8 @@
#include "embedding_visualizer.hpp"
+#include
+#include
+
using namespace majorminer;
namespace fs = std::filesystem;
@@ -37,11 +40,14 @@ void EmbeddingVisualizer::setupDrawing(const embedding_mapping_t& embedding)
m_embedding = &embedding;
m_svg << m_prepared;
- double fontSize = getWidth() / 30;
+ double fontSize = std::min(getWidth() / 30, 40.0);
+ double y = 50 + fontSize / 2.0;
std::stringstream titleText {};
titleText << "Iteration " << (m_iteration + 1) << ": ";
- m_svg << "" << titleText.str();
+ m_svg << "" << titleText.str();
}
void EmbeddingVisualizer::draw(const embedding_mapping_t& embedding, const char* title)
@@ -311,3 +317,27 @@ double KingsVisualizer::getHeight() const
{
return ((1 + m_nbRows * 2) * getNodeSize());
}
+
+
+fuint32_t GenericVisualizer::insertEdge(Vector& /* coords */, const edge_t& /* edge */)
+{
+ return 0;
+}
+
+Coordinate_t GenericVisualizer::insertNode(fuint32_t v) const
+{
+ auto findIt = m_coordinates.find(v);
+ if (findIt == m_coordinates.end()) throw std::runtime_error("Node not contained in coordinate map!");
+
+ return Coordinate_t{ (1 + findIt->second.first) * getNodeSize(), (1 + findIt->second.second) * getNodeSize() };
+}
+
+double GenericVisualizer::getWidth() const
+{
+ return ((2 + m_width) * getNodeSize());
+}
+
+double GenericVisualizer::getHeight() const
+{
+ return ((2 + m_height) * getNodeSize());
+}
diff --git a/src/common/embedding_visualizer.hpp b/src/common/embedding_visualizer.hpp
index 6908429..68f88ae 100644
--- a/src/common/embedding_visualizer.hpp
+++ b/src/common/embedding_visualizer.hpp
@@ -4,8 +4,6 @@
#include "majorminer_types.hpp"
#include
-#include
-#include
namespace majorminer
{
@@ -109,6 +107,30 @@ namespace majorminer
fuint32_t m_nbRows;
fuint32_t m_nbCols;
};
+
+ typedef UnorderedMap coordinate_map_t;
+ class GenericVisualizer : public EmbeddingVisualizer
+ {
+ public:
+ GenericVisualizer(const graph_t& source, const graph_t& target,
+ std::string filename, const coordinate_map_t& coordinates,
+ double width, double height)
+ : EmbeddingVisualizer(source, target, std::move(filename)),
+ m_coordinates(coordinates), m_width(width), m_height(height) {}
+
+ ~GenericVisualizer(){}
+
+ protected:
+ fuint32_t insertEdge(Vector& coords, const edge_t& edge) override;
+ Coordinate_t insertNode(fuint32_t v) const override;
+ double getWidth() const override;
+ double getHeight() const override;
+
+ private:
+ const coordinate_map_t& m_coordinates;
+ double m_width;
+ double m_height;
+ };
}
diff --git a/src/common/graph_gen.cpp b/src/common/graph_gen.cpp
index 6677175..a673d59 100644
--- a/src/common/graph_gen.cpp
+++ b/src/common/graph_gen.cpp
@@ -1,5 +1,12 @@
#include "graph_gen.hpp"
+#include
+#include
+#include
+#include
+
+#include
+
using namespace majorminer;
graph_t majorminer::generate_chimera(fuint32_t rows, fuint32_t cols)
@@ -197,3 +204,19 @@ graph_t majorminer::generate_petersen()
};
return petersen;
}
+
+
+graph_t majorminer::generate_erdosrenyi(fuint32_t n, float probability)
+{
+ ProbabilisticDecision rand{};
+ graph_t erdos{};
+ for (fuint32_t i = 0; i < n; ++i)
+ {
+ for (fuint32_t j = i + 1; j < n; ++j)
+ {
+ if (rand(probability)) erdos.insert(std::make_pair(i,j));
+ }
+ }
+ return erdos;
+}
+
diff --git a/src/common/graph_gen.hpp b/src/common/graph_gen.hpp
index 93621ae..28d39c0 100644
--- a/src/common/graph_gen.hpp
+++ b/src/common/graph_gen.hpp
@@ -1,12 +1,6 @@
#ifndef __MAJORMINER_GRAPH_GEN_HPP_
#define __MAJORMINER_GRAPH_GEN_HPP_
-#include
-#include
-#include
-#include
-#include
-
#include "majorminer_types.hpp"
@@ -37,6 +31,10 @@ namespace majorminer
/// Import an edge list from a character array.
graph_t import_graph(const char* edgeList, size_t length);
+ // Generate an erdös-renyi graph on n vertices. For each pair of vertices
+ // create an edge between the pair with "probability"
+ graph_t generate_erdosrenyi(fuint32_t n, float probability);
+
}
diff --git a/src/common/graph_info.cpp b/src/common/graph_info.cpp
new file mode 100644
index 0000000..c5835d8
--- /dev/null
+++ b/src/common/graph_info.cpp
@@ -0,0 +1,15 @@
+#include
+
+using namespace majorminer;
+
+fuint32_t ChimeraGraphInfo::getXCoord(vertex_t vertex) const
+{
+ return (vertex % (m_width * 8)) / 8;
+}
+
+fuint32_t ChimeraGraphInfo::getYCoord(vertex_t vertex) const
+{
+ return vertex / (m_width * 8);
+}
+
+
diff --git a/src/common/graph_info.hpp b/src/common/graph_info.hpp
new file mode 100644
index 0000000..4e15d3f
--- /dev/null
+++ b/src/common/graph_info.hpp
@@ -0,0 +1,43 @@
+#ifndef __MAJORMINER_GRAPH_INFO_HPP_
+#define __MAJORMINER_GRAPH_INFO_HPP_
+
+#include
+
+namespace majorminer
+{
+
+ struct ChimeraGraphInfo
+ {
+ ChimeraGraphInfo(): m_width(0), m_height(0) {}
+ ChimeraGraphInfo(fuint32_t width, fuint32_t height)
+ : m_width(width), m_height(height) {}
+
+ fuint32_t getXCoord(vertex_t vertex) const;
+ fuint32_t getYCoord(vertex_t vertex) const;
+ fuint32_t getWidth() const { return m_width; }
+ fuint32_t getHeight() const { return m_height; }
+
+ fuint32_t m_width;
+ fuint32_t m_height;
+ };
+
+ struct KingGraphInfo
+ {
+ KingGraphInfo(): m_width(0), m_height(0) {}
+ KingGraphInfo(fuint32_t width, fuint32_t height)
+ : m_width(width), m_height(height) {}
+
+ fuint32_t getXCoord(vertex_t vertex) const { return vertex % m_width; }
+ fuint32_t getYCoord(vertex_t vertex) const { return vertex / m_width; }
+ fuint32_t getWidth() const { return m_width; }
+ fuint32_t getHeight() const { return m_height; }
+
+ fuint32_t m_width;
+ fuint32_t m_height;
+ };
+}
+
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/random_gen.cpp b/src/common/random_gen.cpp
new file mode 100644
index 0000000..7633e32
--- /dev/null
+++ b/src/common/random_gen.cpp
@@ -0,0 +1,30 @@
+#include "common/random_gen.hpp"
+
+using namespace majorminer;
+RandomGen::RandomGen()
+ : m_generator(m_rdGen()),
+ m_shuffleGenerator(m_rdShuffle())
+{}
+
+fuint32_t RandomGen::getRandomUint(fuint32_t upper)
+{
+ std::uniform_int_distribution distribution(0, upper);
+ while(!m_lock.try_lock()) {}
+
+ fuint32_t randomVal = distribution(m_generator);
+
+ m_lock.unlock();
+ return randomVal;
+}
+
+
+vertex_t RandomGen::getRandomVertex(const nodeset_t& vertices)
+{
+ if (vertices.empty()) return FUINT32_UNDEF;
+ fuint32_t idx = getRandomUint(vertices.size() - 1);
+ for (auto vertex : vertices)
+ {
+ if (idx-- == 0) return vertex;
+ }
+ return FUINT32_UNDEF;
+}
\ No newline at end of file
diff --git a/src/common/random_gen.hpp b/src/common/random_gen.hpp
new file mode 100644
index 0000000..1e610da
--- /dev/null
+++ b/src/common/random_gen.hpp
@@ -0,0 +1,53 @@
+#ifndef __MAJORMINER_RANDOM_GEN_HPP_
+#define __MAJORMINER_RANDOM_GEN_HPP_
+
+#include
+
+namespace majorminer
+{
+
+ class RandomGen
+ {
+ public:
+ RandomGen();
+ fuint32_t getRandomUint(fuint32_t upper);
+
+ template
+ void shuffle(T* data, fuint32_t size)
+ {
+ if (size == 0) return;
+ while(!m_shuffleLock.try_lock()) {}
+
+ std::shuffle(data, data + size, m_shuffleGenerator);
+
+ m_shuffleLock.unlock();
+ }
+
+ vertex_t getRandomVertex(const nodeset_t& vertices);
+
+ private:
+ std::mutex m_lock;
+ std::mutex m_shuffleLock;
+ std::random_device m_rdGen;
+ std::random_device m_rdShuffle;
+ std::default_random_engine m_generator;
+ std::default_random_engine m_shuffleGenerator;
+ };
+
+ template::value>>
+ struct ProbabilisticDecision
+ {
+ public:
+ ProbabilisticDecision() : m_gen(m_rd()), m_dist(static_cast(0.0), static_cast(1.0)) {}
+ T operator()() { return m_dist(m_gen); }
+ bool operator()(T value) { return m_dist(m_gen) < value; }
+
+ private:
+ std::random_device m_rd;
+ std::mt19937 m_gen;
+ std::uniform_real_distribution m_dist;
+ };
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/thread_manager.cpp b/src/common/thread_manager.cpp
new file mode 100644
index 0000000..e69de29
diff --git a/src/common/thread_manager.hpp b/src/common/thread_manager.hpp
new file mode 100644
index 0000000..eb1a3b5
--- /dev/null
+++ b/src/common/thread_manager.hpp
@@ -0,0 +1,39 @@
+#ifndef __MAJORMINER_THREAD_MANAGER_HPP_
+#define __MAJORMINER_THREAD_MANAGER_HPP_
+
+#include
+#include
+
+namespace majorminer
+{
+
+ class ThreadManager
+ {
+ public:
+ ThreadManager(){}
+
+ fuint32_t getAvailableThreads() const { return m_pool.get_thread_count(); }
+
+ template
+ void runMultiple(const Functor& func, fuint32_t n)
+ {
+ for (fuint32_t i = 0; i < n; ++i) m_pool.push_task(func);
+ }
+
+ template
+ void run(const Functor& func)
+ {
+ m_pool.push_task(func);
+ }
+
+ void wait() { m_pool.wait_for_tasks(); }
+
+ private:
+ thread_pool m_pool;
+
+ };
+
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/common/time_measurement.cpp b/src/common/time_measurement.cpp
new file mode 100644
index 0000000..4bb204b
--- /dev/null
+++ b/src/common/time_measurement.cpp
@@ -0,0 +1,9 @@
+#include "common/time_measurement.hpp"
+
+namespace majorminer
+{
+
+double TIME_MUTATION = 0, TIME_REDUCE = 0;
+double GENERATE_POP = 0, OPTIMIZE = 0;
+
+}
diff --git a/src/common/time_measurement.hpp b/src/common/time_measurement.hpp
new file mode 100644
index 0000000..a81d57d
--- /dev/null
+++ b/src/common/time_measurement.hpp
@@ -0,0 +1,23 @@
+#ifndef __MAJORMINER_TIME_MEASUREMENT_HPP_
+#define __MAJORMINER_TIME_MEASUREMENT_HPP_
+
+#include
+
+#define CHRONO_STUFF(t1, t2, diff, var, ...) \
+ auto t1 = std::chrono::high_resolution_clock::now(); \
+ __VA_ARGS__ \
+ auto t2 = std::chrono::high_resolution_clock::now(); \
+ std::chrono::duration diff = t2 - t1; \
+ var+=diff.count();
+
+
+#define PRINT_TIME(name) std::cout << "Time: " << #name << ": " << name << std::endl;
+
+namespace majorminer
+{
+ extern double TIME_MUTATION, TIME_REDUCE;
+ extern double GENERATE_POP, OPTIMIZE;
+}
+
+
+#endif
diff --git a/src/common/utils.cpp b/src/common/utils.cpp
index 1a78bec..414d971 100644
--- a/src/common/utils.cpp
+++ b/src/common/utils.cpp
@@ -1,4 +1,6 @@
-#include "utils.hpp"
+#include "common/utils.hpp"
+
+#include
using namespace majorminer;
@@ -13,10 +15,71 @@ void majorminer::convertToAdjacencyList(adjacency_list_t& adj, const graph_t& gr
});
}
-void majorminer::printAdjacencyList(const adjacency_list_t& adj)
+
+void majorminer::insertMappedTargetNodes(const EmbeddingBase& base, nodeset_t& nodes, fuint32_t sourceNode)
+{
+ const auto& mapping = base.getMapping();
+ auto equalRange = mapping.equal_range(sourceNode);
+ for (auto it = equalRange.first; it != equalRange.second; ++it) nodes.insert(it->second);
+}
+
+nodeset_t majorminer::getVertices(const graph_t& graph)
+{
+ nodeset_t vertices{};
+ for (const auto& edge : graph)
+ {
+ vertices.insert(edge.first);
+ vertices.insert(edge.second);
+ }
+ return vertices;
+}
+
+
+fuint32_pair_t majorminer::calculateOverlappingStats(const EmbeddingBase& base)
+{
+ fuint32_t distinct = 0;
+ fuint32_t total = 0;
+ nodeset_t targetVertices = getVertices(*base.getTargetGraph());
+ const auto& reverse = base.getReverseMapping();
+
+ for (auto target : targetVertices)
+ {
+ fuint32_t nbMapped = reverse.count(target);
+ if (nbMapped >= 2)
+ {
+ distinct++;
+ total += nbMapped;
+ }
+ }
+ return std::make_pair(distinct, total);
+}
+
+embedding_mapping_t majorminer::replaceMapping(const embedding_mapping_t& mapping,
+ const nodeset_t& targets, vertex_t source)
{
- for (const auto& edge : adj)
+ embedding_mapping_t adjusted{};
+ adjusted.insert(mapping.begin(), mapping.end());
+ adjusted.unsafe_erase(source);
+ for (auto target : targets)
{
- std::cout << "(" << edge.first << ", " << edge.second << ")" << std::endl;
+ adjusted.insert(std::make_pair(source, target));
}
+ return adjusted;
}
+
+fuint32_t majorminer::calculateFitness(const EmbeddingBase& state, const nodeset_t& superVertex)
+{
+ const auto& reverse = state.getReverseMapping();
+ fuint32_t fitness = 0;
+ for (vertex_t target : superVertex)
+ {
+ fitness += reverse.count(target);
+ }
+ return fitness;
+}
+
+bool majorminer::containsEdge(const graph_t& graph, edge_t edge)
+{
+ return graph.contains(orderedPair(edge));
+}
+
diff --git a/src/common/utils.hpp b/src/common/utils.hpp
index e842418..7c6e72c 100644
--- a/src/common/utils.hpp
+++ b/src/common/utils.hpp
@@ -1,9 +1,8 @@
#ifndef __MAJORMINER_UTILS_HPP_
#define __MAJORMINER_UTILS_HPP_
-#include
-
-#include "majorminer_types.hpp"
+#include
+#include
namespace majorminer
@@ -29,8 +28,6 @@ namespace majorminer
template
void setMax(T& val, const T& v) { if (v > val) val = v; }
- void printAdjacencyList(const adjacency_list_t& adj);
-
template
void eraseSinglePair(UnorderedMultiMap& umap, const K& key, const V& val)
{
@@ -44,6 +41,83 @@ namespace majorminer
}
}
}
+
+ template
+ bool containsPair(const UnorderedMultiMap& umap, const K& key, const V& val)
+ {
+ auto range = umap.equal_range(key);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ if (it->second == val)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void insertMappedTargetNodes(const EmbeddingBase& base, nodeset_t& nodes, fuint32_t sourceNode);
+
+ inline bool isDefined(fuint32_t value) { return value != FUINT32_UNDEF; }
+ inline bool isDefined(fuint32_pair_t& p) { return isDefined(p.first) && isDefined(p.second); }
+ inline bool isDefined(NodePair& p) { return isDefined(p.source) && isDefined(p.target); }
+
+ template
+ inline std::shared_ptr make_shared_array(std::size_t size)
+ {
+ return std::shared_ptr( new T[size], []( T *p ){ delete [] p; } );
+ }
+
+ template
+ inline bool overlappingSets(const UnorderedSet& map1, const UnorderedSet& map2)
+ {
+ for (const auto& key : map1)
+ {
+ if (map2.contains(key)) return true;
+ }
+ return false;
+ }
+
+ template
+ inline void clearStack(Stack& s)
+ {
+ while(!s.empty()) s.pop();
+ }
+
+ nodeset_t getVertices(const graph_t& graph);
+
+ fuint32_pair_t calculateOverlappingStats(const EmbeddingBase& base);
+
+ // inefficient - just for visualization
+ embedding_mapping_t replaceMapping(const embedding_mapping_t& mapping,
+ const nodeset_t& targets, vertex_t source);
+
+ template
+ inline std::pair reversePair(const std::pair& p)
+ {
+ return std::make_pair(p.second, p.first);
+ }
+
+ template
+ struct PairFirstKeySorter
+ {
+ bool operator()(const std::pair& p1, const std::pair& p2)
+ {
+ if(reverse) return p1.first < p2.first;
+ else return p1.first > p2.first;
+ }
+ };
+
+ // Calculate the fitness of an *unmapped* super vertex! Calculate number of overlappings
+ fuint32_t calculateFitness(const EmbeddingBase& state, const nodeset_t& superVertex);
+
+ bool containsEdge(const graph_t& graph, edge_t edge);
+
+ template
+ inline bool empty_range(const std::pair& range)
+ {
+ return range.first == range.second;
+ }
}
diff --git a/src/evolutionary/CMakeLists.txt b/src/evolutionary/CMakeLists.txt
index e876882..36c3438 100644
--- a/src/evolutionary/CMakeLists.txt
+++ b/src/evolutionary/CMakeLists.txt
@@ -1,6 +1,7 @@
target_sources(majorminer PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/mutation_manager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mutation_extend.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/frontier_shifting_data.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mutation_frontier_shifting.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mutation_reduce_overlap.cpp
)
\ No newline at end of file
diff --git a/src/evolutionary/frontier_shifting_data.cpp b/src/evolutionary/frontier_shifting_data.cpp
deleted file mode 100644
index 7acbfaa..0000000
--- a/src/evolutionary/frontier_shifting_data.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "frontier_shifting_data.hpp"
-
-using namespace majorminer;
-
-
-
-void FrontierShiftingData::clear()
-{
- m_victimSourceNode = -1;
- m_victimSubgraph.clear();
- m_cutVertices.clear();
- m_victimConnections.clear();
- m_reverseConnections.clear();
-}
-
-void FrontierShiftingData::lostNode(fuint32_t conquered, fuint32_t conquerorSource)
-{
- if (m_nbNodes <= 1) throw std::runtime_error("Bad number of nodes in frontiershifting data.");
- m_nbNodes--;
- m_cutVertices.clear();
- auto range = m_reverseConnections.equal_range(conquered);
- for (auto it = range.first; it != range.second; ++it)
- {
- eraseSinglePair(m_victimConnections, it->second, it->first);
- }
- m_reverseConnections.unsafe_erase(range.first, range.second);
- nodeset_t newConnections{};
- for (auto it = m_victimSubgraph.begin(); it !=m_victimSubgraph.end();)
- {
- if(it->first == conquered)
- {
- m_victimConnections.insert(edge_t{conquerorSource, it->second});
- m_reverseConnections.insert(edge_t{it->second, conquerorSource});
- }
- if (it->first == conquered || it->second == conquered)
- {
- it = m_victimSubgraph.unsafe_erase(it);
- }
- else ++it;
- }
-}
-
-void FrontierShiftingData::addConnection(fuint32_t sourceFrom, fuint32_t targetTo)
-{
- m_victimConnections.insert(edge_t{ sourceFrom, targetTo });
- m_reverseConnections.insert(edge_t{ targetTo, sourceFrom });
-}
-
-void FrontierShiftingData::findCutVertices()
-{
- // frontiershifting is not allowed on cut vertices as removing them would
- // disconnect the chain. Therefore, identify cut vertices beforehand
- majorminer::identifiyCutVertices(m_cutVertices, m_victimSubgraph, m_nbNodes);
-}
-
-void FrontierShiftingData::setNbNodes(fuint32_t nbNodes)
-{
- m_nbNodes = nbNodes;
-}
-
-bool FrontierShiftingData::isNowACutVertex(fuint32_t contested) const
-{
- return majorminer::isCutVertex(m_victimSubgraph, contested, m_nbNodes);
-}
-
-void FrontierShiftingData::setVictimSource(fuint32_t node)
-{
- m_victimSourceNode = node;
-}
-
diff --git a/src/evolutionary/frontier_shifting_data.hpp b/src/evolutionary/frontier_shifting_data.hpp
deleted file mode 100644
index bc96733..0000000
--- a/src/evolutionary/frontier_shifting_data.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __MAJORMINER_FRONTIER_SHIFTING_DATA_HPP_
-#define __MAJORMINER_FRONTIER_SHIFTING_DATA_HPP_
-
-#include "majorminer_types.hpp"
-#include "common/cut_vertex.hpp"
-#include "common/utils.hpp"
-
-
-namespace majorminer
-{
-
- struct FrontierShiftingData
- {
- FrontierShiftingData() : m_victimSourceNode((fuint32_t)-1) { }
- void clear();
- void setNbNodes(fuint32_t nbNodes);
- void setVictimSource(fuint32_t node);
- void lostNode(fuint32_t conquered, fuint32_t conquerorSource);
- void addConnection(fuint32_t sourceFrom, fuint32_t targetTo);
- void findCutVertices();
- bool isNowACutVertex(fuint32_t contested) const;
-
-
- fuint32_t m_victimSourceNode;
- fuint32_t m_nbNodes;
- adjacency_list_t m_victimSubgraph;
- nodeset_t m_cutVertices;
-
- // source node (connected to victim) --> target node mapped to from victim
- adjacency_list_t m_victimConnections; // all connections other nodes have to the victim's chain
- adjacency_list_t m_reverseConnections; // reverse m_victimConnections
- };
-
-}
-
-#endif
\ No newline at end of file
diff --git a/src/evolutionary/generic_mutation.hpp b/src/evolutionary/generic_mutation.hpp
index cc51591..03e7b8c 100644
--- a/src/evolutionary/generic_mutation.hpp
+++ b/src/evolutionary/generic_mutation.hpp
@@ -9,7 +9,24 @@ namespace majorminer
{
public:
virtual ~GenericMutation() {}
+
+ // fast check whether a mutation is still valid
+ virtual bool isValid() = 0;
+
+ // Initial preparation or revalidating a preparation
+ virtual bool prepare() = 0;
+
+ // Incorporate changes of this mutation
virtual void execute() = 0;
+
+ // Should an invalid mutation be requeued? Default: Yes.
+ virtual bool requeue() const { return true; }
+
+ protected:
+ void generateTimestamp();
+
+ private:
+ fuint32_t m_timestamp;
};
}
diff --git a/src/evolutionary/mutation_extend.cpp b/src/evolutionary/mutation_extend.cpp
index 70414aa..fb0d6f4 100644
--- a/src/evolutionary/mutation_extend.cpp
+++ b/src/evolutionary/mutation_extend.cpp
@@ -1,123 +1,98 @@
-#include "mutation_extend.hpp"
+#include "evolutionary/mutation_extend.hpp"
+
+#include
+#include
+#include
+
+#include
using namespace majorminer;
-MutationExtend::MutationExtend(EmbeddingSuite* suite, fuint32_t sourceNode)
- : m_suite(*suite) {
- // check whether node needs more
- int delta = std::max(suite->numberFreeNeighborsNeeded(sourceNode), 0);
- if (delta == 0) return;
+MutationExtend::MutationExtend(const EmbeddingState& state, EmbeddingManager& embeddingManager, fuint32_t sourceNode)
+ : m_state(state), m_embeddingManager(embeddingManager), m_sourceVertex(sourceNode),
+ m_time(m_embeddingManager.getTimestamp()) { }
- // find adjacent target node with highest number
- auto mapRange = suite->m_mapping.equal_range(sourceNode);
+// use embedding manager only
+void MutationExtend::execute()
+{
+ // std::cout << "1. Extend execute node "<m_target.equal_range(targetNode->second);
- for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
+ m_embeddingManager.commit();
+
+ if (m_state.hasVisualizer())
{
- if (m_suite.m_targetNodesRemaining.contains(adj->second))
- { // legitimate candidate
- auto improvement = checkCandidate(adj->second, sourceNode, delta);
- if (improvement < bestVal)
- {
- bestVal = improvement;
- bestExtend = adj->second;
- adjTargetNode = targetNode->second;
- }
- }
+ std::stringstream ss;
+ ss << "ExtendMutation applied " << m_sourceVertex
+ << " -> { ..., " << m_extendedTarget << " }; improvement: "
+ << improvement << std::endl;
+ m_embeddingManager.getVisualizer()->draw(m_embeddingManager.getMapping(), ss.str().c_str());
}
}
-
- if (bestVal < 0)
- {
- DEBUG(OUT_S << "Emitting extend task for sourceNode=" << sourceNode
- << " to extend to " << bestExtend << ". Improvement: "
- << bestVal << std::endl;)
- m_sourceVertex = sourceNode;
- m_targetVertex = adjTargetNode;
- m_extendedTarget = bestExtend;
- m_valid = true;
- }
}
-double MutationExtend::checkCandidate(fuint32_t extendNode, fuint32_t sourceNode, int delta)
+double MutationExtend::checkImprovement(fuint32_t extendNode, const EmbeddingBase& base)
{
- m_degraded.clear();
+ const auto& remainingTargetNodes = base.getRemainingTargetNodes();
double improvement = 0;
-
- auto adjRange = m_suite.m_target.equal_range(extendNode);
- int nbFree = 0;
- for (auto adj = adjRange.first; adj != adjRange.second; ++adj)
- {
- if (m_suite.m_targetNodesRemaining.contains(adj->second)) nbFree++;
- else
- { // already mapped to
- // go over each that was mapped to this node and add to degraded
- auto revIt = m_suite.m_reverseMapping.equal_range(adj->second);
- for (auto rev = revIt.first; rev != revIt.second; ++rev)
- {
- m_degraded.insert(rev->second);
- }
- }
- }
- if (nbFree == 0) return MAXFLOAT;
- improvement = - std::min(delta, nbFree) + 1;
- for (auto deg : m_degraded)
- {
- if (improvement >= 0) return MAXFLOAT;
- if (deg == extendNode) continue;
- else
- {
- int needed = m_suite.numberFreeNeighborsNeeded(deg);
- if (needed > -1) improvement++;
- }
- }
+ base.iterateTargetGraphAdjacent(extendNode, [&](fuint32_t adjacent){
+ if (!remainingTargetNodes.contains(adjacent)) improvement -= 1;
+ });
return improvement;
}
-void MutationExtend::execute()
+bool MutationExtend::prepare()
{
- if(!m_valid || !m_suite.m_targetNodesRemaining.contains(m_extendedTarget)) return;
- int delta = m_suite.numberFreeNeighborsNeeded(m_sourceVertex);
- if (delta <= 0) return;
- double improvement = checkCandidate(m_extendedTarget, m_sourceVertex, delta);
- if (improvement < 0)
- { // adopt mutation
- m_suite.m_targetNodesRemaining.unsafe_erase(m_extendedTarget);
- m_suite.m_nodesOccupied.insert(m_extendedTarget);
- m_suite.m_mapping.insert(std::make_pair(m_sourceVertex, m_extendedTarget));
- m_suite.m_reverseMapping.insert(std::make_pair(m_extendedTarget, m_sourceVertex));
+ int delta = std::max(m_state.numberFreeNeighborsNeeded(m_sourceVertex), 0);
+ // std::cout << "Extend - node m_sourceVertex " << m_sourceVertex << " has delta of " << delta << std::endl;
+ if (delta == 0) return false;
+ const auto& remainingTargetNodes = m_state.getRemainingTargetNodes();
- for (auto deg : m_degraded)
- {
- if (deg != m_sourceVertex) m_suite.m_sourceFreeNeighbors[deg]--;
- }
- m_degraded.clear();
- auto embRange = m_suite.m_mapping.equal_range(m_sourceVertex);
- for (auto embIt = embRange.first; embIt != embRange.second; ++embIt)
- {
- auto adjRange = m_suite.m_target.equal_range(embIt->second);
- for (auto adjIt = adjRange.first; adjIt != adjRange.second; ++adjIt)
- {
- if (m_suite.m_targetNodesRemaining.contains(adjIt->second))
- { m_degraded.insert(adjIt->second); }
- }
- }
- m_suite.m_sourceFreeNeighbors[m_sourceVertex] = m_degraded.size();
+ double bestVal = MAXFLOAT;
+ fuint32_t bestExtend = -1;
- if (m_suite.m_visualizer != nullptr)
+ nodeset_t candidates{};
+ m_state.iterateSourceMappingAdjacent(m_sourceVertex, [&](fuint32_t neighbor, fuint32_t){
+ if (remainingTargetNodes.contains(neighbor)) candidates.insert(neighbor);
+ return false;
+ });
+
+ for (auto& candidate : candidates)
+ {
+ double improvement = checkImprovement(candidate, m_state);
+ if (improvement < bestVal)
{
- std::stringstream ss;
- ss << "ExtendMutation applied " << m_sourceVertex
- << " -> { ..., " << m_extendedTarget << " }; improvement: "
- << improvement << std::endl;
- m_suite.m_visualizer->draw(m_suite.m_mapping, ss.str().c_str());
+ bestVal = improvement;
+ bestExtend = candidate;
}
}
+ m_improving = bestVal < 0;
+ m_extendedTarget = bestExtend;
+
+ m_time = m_embeddingManager.getTimestamp();
+ return m_improving;
}
+
+bool MutationExtend::isValid()
+{
+ // std::cout << "Time" << m_time << std::endl;
+ // std::cout <<"History "<< m_embeddingManager.getHistory(m_sourceVertex).m_timestampNodeChanged <
+#include
+#include
+#include
+#include
+
+#include
+
+#define MAX_CANDIDATES 20
+
using namespace majorminer;
+namespace
+{
+ bool isCandidateValid(const ShiftingCandidates& candidate)
+ {
+ return candidate.second.get() != nullptr;
+ }
+}
+
+MutationFrontierShifting::MutationFrontierShifting(const EmbeddingState& state, EmbeddingManager& manager,
+ fuint32_t conquerorSource)
+ : m_state(state), m_manager(manager), m_conqueror(conquerorSource),
+ m_victim(FUINT32_UNDEF), m_valid(false)
+{ }
+bool MutationFrontierShifting::isValid()
+{
+ // std::cout << "Valid=" << m_valid << "; bestContested=" << m_bestContested << "; improvement=" << calculateImprovement(m_victim)
+ // << "; crucial=" << !isNodeCrucial(m_manager, m_victim, m_bestContested, m_conqueror) << std::endl;
+ // std::cout << "Victim=" << m_victim << "; Conqueror=" << m_conqueror << std::endl;
+ //char c=getchar();
+ //if (c=='E') return false;
+ // std::cout << "------------------------------" << std::endl;
+ return m_valid
+ && containsPair(m_manager.getMapping(), m_victim, m_bestContested)
+ && isDefined(m_bestContested) && calculateImprovement(m_victim) < 0
+ && !isNodeCrucial(m_manager, m_victim, m_bestContested, m_conqueror);
+}
-MuationFrontierShifting::MuationFrontierShifting(EmbeddingSuite* suite,
- fuint32_t conquerorSource, fuint32_t victimSource)
- : m_suite(*suite), m_conqueror(conquerorSource),
- m_victim(victimSource), m_valid(false)
+bool MutationFrontierShifting::prepare()
{
// find a victim node for which conqueror is connected to and
// all other node is not crucial for victim
- auto& data = m_suite.m_frontierData;
- auto conquerorRange = data.m_victimConnections.equal_range(conquerorSource);
-
- for (auto candidateIt = conquerorRange.first; candidateIt != conquerorRange.second; ++candidateIt)
+ // std::cout << "Preparing shifting. " << m_conqueror << std::endl;
+ m_valid = false;
+ ShiftingCandidates cands = m_manager.getCandidatesFor(m_conqueror);
+ if (!isCandidateValid(cands) || true )
{
- if (data.m_cutVertices.contains(candidateIt->second) || isCrucial(candidateIt->second)) continue;
- double val = calculateImprovement(candidateIt->second);
- if (val < m_bestImprovement)
- {
- m_bestImprovement = val;
- m_valid = true;
- m_bestContested = candidateIt->second;
- }
+ nodepairset_t candidateSet{};
+ m_state.iterateSourceMappingAdjacent(m_conqueror, [&](fuint32_t target, fuint32_t){
+ m_state.iterateReverseMapping(target, [&](fuint32_t cand){
+ if (cand != m_conqueror) candidateSet.insert(fuint32_pair_t{cand, target});
+ });
+ return candidateSet.size() > MAX_CANDIDATES;
+ });
+ cands = m_manager.setCandidatesFor(m_conqueror, candidateSet);
}
-}
-bool MuationFrontierShifting::isCrucial(fuint32_t candidateNode)
-{
- auto& data = m_suite.m_frontierData;
- auto revRange = data.m_reverseConnections.equal_range(candidateNode);
- for (auto revIt = revRange.first; revIt != revRange.second; ++revIt)
- { // for every node, we have to make sure that the source node has another
- // connection to the victim chain
- if (revIt->second == m_conqueror) continue;
- bool replaceable = false;
- auto connectionRange = data.m_victimConnections.equal_range(revIt->second);
- for (auto it = connectionRange.first; it != connectionRange.second; ++it)
+ if (!isCandidateValid(cands)) return false;
+ fuint32_pair_t* candidates = cands.second.get();
+ auto subgraph = extractSubgraph(m_state, m_conqueror);
+
+ for (fuint32_t idx = 0; idx < cands.first; ++idx)
+ {
+ fuint32_pair_t candidate = candidates[idx];
+ candidates[idx] = std::make_pair(FUINT32_UNDEF, FUINT32_UNDEF);
+
+ if (!isDefined(candidate)) continue;
+ double improvement = calculateImprovement(candidate.first);
+ // std::cout << "Shifting " << m_conqueror << " - (" << candidate.first << "," << candidate.second << "): " << improvement << std::endl;
+ //if (improvement < 0) { char c = getchar(); if (c == 'E') return false; }
+ if (improvement < 0 && !isNodeCrucial(m_state, candidate.first, candidate.second, m_conqueror))
{
- if (it->second != candidateNode)
- {
- replaceable = true;
- break;
- }
+ // std::cout << "Found valid shifting!" << std::endl;
+ m_bestImprovement = improvement;
+ m_valid = true;
+ m_bestContested = candidate.second;
+ m_victim = candidate.first;
+ break;
}
- if (!replaceable) return true;
}
- return false;
+ return m_valid;
}
-double MuationFrontierShifting::calculateImprovement(fuint32_t candidateNode)
-{
- // Two factors play a role:
- // 1. Change in chain length
- // 2. Change in free neighbors
- // TODO: add free neighbor calculation
- fuint32_t victimLength = m_suite.m_mapping.count(m_victim);
- fuint32_t conquerorLength = m_suite.m_mapping.count(m_conqueror);
+double MutationFrontierShifting::calculateImprovement(fuint32_t victim)
+{ // todo: generic on EmbeddingBase
+ int victimLength = static_cast(m_state.getSuperVertexSize(victim));
+ int conquerorLength = static_cast(m_state.getSuperVertexSize(m_conqueror));
if (victimLength == 0) return MAXFLOAT;
return pow(victimLength - 1, 2) + pow(conquerorLength + 1, 2)
- pow(victimLength, 2) - pow(conquerorLength, 2);
}
-void MuationFrontierShifting::execute()
+void MutationFrontierShifting::execute()
{
- auto& data = m_suite.m_frontierData;
- if (!m_valid || isCrucial(m_bestContested)) return;
- if (data.isNowACutVertex(m_bestContested) || calculateImprovement(m_bestContested) >= 0) return;
-
- // Commit the mutation
- eraseSinglePair(m_suite.m_mapping, m_victim, m_bestContested);
- eraseSinglePair(m_suite.m_reverseMapping, m_bestContested, m_victim);
- m_suite.m_mapping.insert(fuint32_pair_t{ m_conqueror, m_bestContested });
- m_suite.m_reverseMapping.insert(fuint32_pair_t{ m_bestContested, m_conqueror });
+ // std::cout << "Conqueror=" << m_conqueror << "; Contested=" << m_bestContested << "; Victim=" << m_victim << std::endl;
+ // getchar();
+ m_manager.deleteMappingPair(m_victim, m_bestContested);
+ if (!containsPair(m_manager.getMapping(), m_conqueror, m_bestContested)) m_manager.insertMappingPair(m_conqueror, m_bestContested);
+ m_manager.commit();
- // take care of free neighbors and update frontierData
- m_suite.m_frontierData.lostNode(m_bestContested, m_conqueror);
- if (m_suite.m_visualizer != nullptr)
+ if (m_state.hasVisualizer())
{
- m_suite.m_visualizer->draw(m_suite.m_mapping, [this](std::ostream& svg)
+ m_manager.getVisualizer()->draw(m_manager.getMapping(), [this](std::ostream& svg)
{
svg << "FrontierShifting. Conqueror "
<< this->getConqueror() << ", victim "
diff --git a/src/evolutionary/mutation_frontier_shifting.hpp b/src/evolutionary/mutation_frontier_shifting.hpp
index 9266398..65f9b2c 100644
--- a/src/evolutionary/mutation_frontier_shifting.hpp
+++ b/src/evolutionary/mutation_frontier_shifting.hpp
@@ -1,30 +1,31 @@
#ifndef __MAJORMINER_MUTATION_FRONTIER_SHIFTING_HPP_
#define __MAJORMINER_MUTATION_FRONTIER_SHIFTING_HPP_
-#include "evolutionary/generic_mutation.hpp"
#include "majorminer_types.hpp"
-#include "majorminer.hpp"
+#include "evolutionary/generic_mutation.hpp"
namespace majorminer
{
- class MuationFrontierShifting : public GenericMutation
+ class MutationFrontierShifting : public GenericMutation
{
public:
- MuationFrontierShifting(EmbeddingSuite* suite, fuint32_t conquerorSource, fuint32_t victimSource);
- ~MuationFrontierShifting() {}
+ MutationFrontierShifting(const EmbeddingState& state, EmbeddingManager& manager, fuint32_t conquerorSource);
+ ~MutationFrontierShifting() {}
void execute() override;
+ bool isValid() override;
+ bool prepare() override;
fuint32_t getConqueror() const { return m_conqueror; }
fuint32_t getVictim() const { return m_victim; }
fuint32_t getContested() const { return m_bestContested; }
private:
- bool isCrucial(fuint32_t candidateNode);
- double calculateImprovement(fuint32_t candidateNode);
+ double calculateImprovement(fuint32_t victim);
private:
- EmbeddingSuite& m_suite;
+ const EmbeddingState& m_state;
+ EmbeddingManager& m_manager;
fuint32_t m_conqueror;
fuint32_t m_victim;
fuint32_t m_bestContested;
diff --git a/src/evolutionary/mutation_manager.cpp b/src/evolutionary/mutation_manager.cpp
new file mode 100644
index 0000000..c0ac374
--- /dev/null
+++ b/src/evolutionary/mutation_manager.cpp
@@ -0,0 +1,152 @@
+#include "evolutionary/mutation_manager.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+using namespace majorminer;
+
+
+void MutationManager::operator()(bool finalIteration)
+{
+ if (!finalIteration) prepare();
+ else prepareFinal();
+ m_done = false;
+ m_runningPreps = 0;
+ m_wait = false;
+
+ // one thread integrating mutations, other threads preparing new mutations
+ auto& prepQueue = m_prepQueue;
+ auto& incorporationQueue = m_incorporationQueue;
+ const auto& done = m_done;
+ auto& runningPreps = m_runningPreps;
+ auto& remaining = m_numberRemaining;
+ auto& free = m_free;
+
+ auto prepareLambda = [&](){
+ MutationPtr mutation;
+ while(!done)
+ {
+ bool success = prepQueue.try_pop(mutation);
+ if (!success) continue;
+ else
+ {
+ free.lock_shared();
+ runningPreps++;
+ free.unlock_shared();
+ bool valid = mutation->prepare();
+ if (valid) incorporationQueue.push(std::move(mutation));
+ else remaining--;
+ runningPreps--;
+ }
+ }
+ };
+
+ auto& threadManager = m_state.getThreadManager();
+ fuint32_t threadCount = std::min(threadManager.getAvailableThreads() - 1, prepQueue.unsafe_size());
+ threadManager.runMultiple(prepareLambda, threadCount);
+ incorporate();
+
+ threadManager.wait();
+ m_embeddingManager.synchronize();
+}
+
+void MutationManager::prepare()
+{
+ clear();
+
+ // insert potential mutations
+ auto lastNode = m_embeddingManager.getLastNode();
+ if (lastNode != (fuint32_t)-1)
+ {
+ prepareMutations(lastNode);
+ }
+ m_numberRemaining = m_prepQueue.unsafe_size();
+}
+
+void MutationManager::prepareFinal()
+{
+ clear();
+ std::vector vertices{};
+ vertices.reserve(m_state.getNumberSourceVertices());
+ const auto& source = m_state.getSourceAdjGraph();
+
+ for (const auto& vertexPair : source)
+ {
+ if (vertices.empty() || vertices.back() != vertexPair.first)
+ {
+ vertices.push_back(vertexPair.first);
+ }
+ }
+
+
+ RandomGen rand{};
+ rand.shuffle(vertices.data(), vertices.size());
+ for (auto vertex : vertices)
+ {
+ m_prepQueue.push(std::make_unique(m_state, m_embeddingManager, vertex));
+ }
+ m_numberRemaining = m_prepQueue.unsafe_size();
+}
+
+void MutationManager::clear()
+{
+ m_embeddingManager.clear();
+ m_prepQueue.clear();
+ m_incorporationQueue.clear();
+}
+
+void MutationManager::prepareMutations(fuint32_t node)
+{
+ nodeset_t affected{};
+ m_state.iterateSourceMappingAdjacent(node, [&](fuint32_t target, fuint32_t /* */){
+ m_state.iterateReverseMapping(target, [&](fuint32_t revSourceNode){
+ affected.insert(revSourceNode);
+ });
+ return false;
+ });
+ affected.insert(node);
+
+ for (auto candidate : affected)
+ {
+ m_prepQueue.push(std::make_unique(m_state, m_embeddingManager, candidate));
+ m_prepQueue.push(std::make_unique(m_state, m_embeddingManager, candidate));
+ }
+}
+
+
+void MutationManager::incorporate()
+{
+ MutationPtr mutation;
+ while(m_numberRemaining > 0)
+ {
+ bool success = m_incorporationQueue.try_pop(mutation);
+ if (!success) continue;
+ bool valid = mutation->isValid();
+ if (!valid && mutation->requeue())
+ {
+ m_prepQueue.push(std::move(mutation));
+ m_wait = true;
+ }
+ else if (valid)
+ {
+ mutation->execute();
+ m_numberRemaining--;
+ }
+ else m_numberRemaining--;
+ if (m_wait)
+ {
+ m_free.lock();
+ while(m_runningPreps != 0) continue;
+ m_embeddingManager.synchronize();
+ m_wait = false;
+ m_free.unlock();
+ }
+ }
+ m_done = true;
+}
diff --git a/src/evolutionary/mutation_manager.hpp b/src/evolutionary/mutation_manager.hpp
new file mode 100644
index 0000000..be7421c
--- /dev/null
+++ b/src/evolutionary/mutation_manager.hpp
@@ -0,0 +1,43 @@
+#ifndef __MAJORMINER_MUTATION_MANAGER_HPP_
+#define __MAJORMINER_MUTATION_MANAGER_HPP_
+
+#include
+
+#include
+
+namespace majorminer
+{
+ class MutationManager
+ {
+ typedef std::unique_ptr MutationPtr;
+
+ public:
+ MutationManager(EmbeddingState& state, EmbeddingManager& embeddingManager)
+ : m_state(state), m_embeddingManager(embeddingManager) {}
+
+ void operator()(bool finalIteration = false);
+
+ private:
+ void clear();
+ void prepare();
+ void prepareFinal();
+ void incorporate();
+ void prepareMutations(fuint32_t node);
+
+ private:
+ EmbeddingState& m_state;
+ EmbeddingManager& m_embeddingManager;
+ Queue m_prepQueue;
+ Queue m_incorporationQueue;
+ std::atomic m_done;
+ std::atomic m_runningPreps;
+ std::atomic m_wait;
+
+ std::atomic m_numberRemaining;
+ std::shared_mutex m_free;
+ };
+
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/evolutionary/mutation_reduce_overlap.cpp b/src/evolutionary/mutation_reduce_overlap.cpp
new file mode 100644
index 0000000..345de79
--- /dev/null
+++ b/src/evolutionary/mutation_reduce_overlap.cpp
@@ -0,0 +1,72 @@
+#include "mutation_reduce_overlap.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+
+using namespace majorminer;
+
+MutationReduceOverlap::MutationReduceOverlap(EmbeddingState& state,
+ EmbeddingManager& manager, fuint32_t sourceVertex)
+ : m_state(state), m_manager(manager), m_sourceVertex(sourceVertex)
+{
+ m_reducer = new SuperVertexReducer{ m_state, sourceVertex };
+}
+
+MutationReduceOverlap::~MutationReduceOverlap()
+{
+ if (m_reducer != nullptr) delete m_reducer;
+}
+
+bool MutationReduceOverlap::isValid()
+{
+ // std::cout << "Checking validity 0x" << ((void*)m_reducer) << std::endl;
+ // bool valid = m_reducer->remainsValid(m_manager);
+ // std::cout << "Is reduce overlap valid?." << valid << std::endl;
+ return m_reducer->remainsValid(m_manager);
+}
+
+bool MutationReduceOverlap::prepare()
+{
+ m_requeues--;
+ m_reducer->initialize();
+ m_reducer->optimize();
+ // std::cout << "Has overlap improved. " << improved << std::endl;
+ return m_reducer->improved();
+}
+
+void MutationReduceOverlap::execute()
+{
+ // std::cout << "Trying to reduce overlap." << std::endl;
+ const auto& initial = m_reducer->getInitialSuperVertex();
+ const auto& improved = m_reducer->getSuperVertex();
+ const auto& reverse = m_manager.getReverseMapping();
+
+ for (auto target : initial)
+ {
+ if (!improved.contains(target))
+ {
+ m_manager.deleteMappingPair(m_sourceVertex, target);
+ if (reverse.count(target) <= 1) m_manager.freeNode(target);
+ }
+ }
+ for (auto target : improved)
+ {
+ if (!initial.contains(target))
+ {
+ m_manager.insertMappingPair(m_sourceVertex, target);
+ m_manager.occupyNode(target);
+ }
+ }
+ m_manager.commit();
+ if (m_state.hasVisualizer())
+ {
+ std::stringstream ss;
+ ss << "ReduceOverlap applied on " << m_sourceVertex << "." << std::endl;
+ m_manager.getVisualizer()->draw(m_manager.getMapping(), ss.str().c_str());
+ }
+}
+
diff --git a/src/evolutionary/mutation_reduce_overlap.hpp b/src/evolutionary/mutation_reduce_overlap.hpp
new file mode 100644
index 0000000..82f3749
--- /dev/null
+++ b/src/evolutionary/mutation_reduce_overlap.hpp
@@ -0,0 +1,33 @@
+#ifndef __MAJORMINER_MUTATION_SIMPLE_REDUCE_OVERLAP_HPP_
+#define __MAJORMINER_MUTATION_SIMPLE_REDUCE_OVERLAP_HPP_
+
+#include
+#include
+
+#define MAX_REQUEUES 5
+
+namespace majorminer
+{
+ class MutationReduceOverlap : public GenericMutation
+ {
+ public:
+ MutationReduceOverlap(EmbeddingState& state, EmbeddingManager& manager, fuint32_t sourceVertex);
+ ~MutationReduceOverlap();
+
+ bool prepare() override;
+ void execute() override;
+ bool isValid() override;
+
+ bool requeue() const override { return m_requeues > 0; }
+
+ private:
+ EmbeddingState& m_state;
+ EmbeddingManager& m_manager;
+ SuperVertexReducer* m_reducer;
+ fuint32_t m_sourceVertex;
+ fuint32_t m_requeues = MAX_REQUEUES;
+ };
+}
+
+
+#endif
\ No newline at end of file
diff --git a/src/initial/CMakeLists.txt b/src/initial/CMakeLists.txt
index 76796eb..8738494 100644
--- a/src/initial/CMakeLists.txt
+++ b/src/initial/CMakeLists.txt
@@ -1,4 +1,7 @@
target_sources(majorminer PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/super_vertex_reducer.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/csc_evolutionary.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/super_vertex_placer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/network_simplex.cpp
)
diff --git a/src/initial/csc_evolutionary.cpp b/src/initial/csc_evolutionary.cpp
new file mode 100644
index 0000000..e591212
--- /dev/null
+++ b/src/initial/csc_evolutionary.cpp
@@ -0,0 +1,544 @@
+#include "initial/csc_evolutionary.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+#define POPULATION_SIZE 5
+#define ITERATION_LIMIT 10
+#define MAX_NEW_VERTICES 15
+#define REDUCE_ITERATION_COEFFICIENT 1
+
+using namespace majorminer;
+
+namespace
+{
+ template
+ void swapPointers(T*& from, T*& to)
+ {
+ T*& temp = to;
+ to = from;
+ from = temp;
+ }
+}
+
+EvolutionaryCSCReducer::EvolutionaryCSCReducer(EmbeddingState& state,
+ vertex_t sourceVertex)
+ : m_state(state), m_sourceVertex(sourceVertex), m_wasPlaced(true),
+ m_improved(false), m_visualizer(nullptr), m_threadManager(state.getThreadManager())
+{
+ initialize();
+}
+
+EvolutionaryCSCReducer::EvolutionaryCSCReducer(EmbeddingState& state,
+ const nodeset_t& initial, vertex_t sourceVertex)
+ : m_state(state), m_sourceVertex(sourceVertex), m_wasPlaced(false),
+ m_improved(false), m_visualizer(nullptr), m_threadManager(state.getThreadManager())
+{
+ initialize(initial);
+}
+
+void EvolutionaryCSCReducer::optimize()
+{
+ if (!m_expansionPossible) return;
+ // double initialFitness = m_bestFitness;
+ Vector* current = &m_populationA;
+ Vector* next = &m_populationB;
+
+ for (fuint32_t iteration = 0; iteration < ITERATION_LIMIT; ++iteration)
+ {
+ CHRONO_STUFF(t1,t2,diff1,OPTIMIZE, optimizeIteration(*current);)
+ if (m_visualizer != nullptr) visualize(iteration + 1, current);
+
+ if (iteration + 1 != ITERATION_LIMIT)
+ {
+ CHRONO_STUFF(t3,t4,diff2,GENERATE_POP,
+ bool success = createNextGeneration(*current, *next);
+ if (!success) break;)
+ swapPointers(current, next);
+ }
+ }
+ if (m_visualizer != nullptr) visualize(FUINT32_UNDEF, nullptr);
+ // PRINT_TIME(TIME_MUTATION)
+ // PRINT_TIME(TIME_REDUCE)
+ // PRINT_TIME(OPTIMIZE)
+ // PRINT_TIME(GENERATE_POP)
+ // std::cout << initialFitness << " to " << m_bestFitness << " (" << m_bestSuperVertex.size() << ")" << std::endl;
+}
+
+#define CREATE_STRING(vertices) \
+ ss << "Final solution with fitness " << getFitness(vertices) << " and size " << vertices.size() << ".";
+
+#define CREATE_IT_STRING(vertices) \
+ ss << "Iteration " << iteration << " individual " << (idx+1) << " has fitness " << getFitness(vertices) << " and size " << vertices.size() << ".";
+
+
+void EvolutionaryCSCReducer::visualize(fuint32_t iteration, Vector* population)
+{
+ if (!isDefined(iteration))
+ {
+ std::stringstream ss;
+ CREATE_STRING(m_bestSuperVertex);
+ embedding_mapping_t adjusted = replaceMapping(m_state.getMapping(), m_bestSuperVertex, m_sourceVertex);
+ m_visualizer->draw(adjusted, ss.str().c_str());
+ }
+ else
+ {
+ std::stringstream ss;
+ for (fuint32_t idx = 0; idx < population->size(); ++idx)
+ {
+ const auto& placement = population->at(idx).getSuperVertex();
+ CREATE_IT_STRING(placement)
+ embedding_mapping_t adjusted = replaceMapping(m_state.getMapping(), placement, m_sourceVertex);
+ m_visualizer->draw(adjusted, ss.str().c_str());
+ ss.str(std::string());
+ }
+ }
+
+}
+
+
+void EvolutionaryCSCReducer::initialize()
+{
+ const auto& mapping = m_state.getMapping();
+ const auto& reverse = m_state.getReverseMapping();
+ auto range = mapping.equal_range(m_sourceVertex);
+ for (auto mappedIt = range.first; mappedIt != range.second; ++mappedIt)
+ {
+ m_bestSuperVertex.insert(mappedIt->second);
+ fuint32_t nbMapped = reverse.count(mappedIt->second);
+ m_vertexFitness.insert(std::make_pair(mappedIt->second,
+ nbMapped >= 1 ? nbMapped - 1 : 0));
+ }
+
+ setup();
+}
+
+void EvolutionaryCSCReducer::initialize(const nodeset_t& initial)
+{
+ m_bestSuperVertex.insert(initial.begin(), initial.end());
+
+ const auto& reverse = m_state.getReverseMapping();
+ for (vertex_t target : m_bestSuperVertex)
+ {
+ m_vertexFitness.insert(std::make_pair(target,
+ reverse.count(target)));
+ }
+ setup();
+}
+
+void EvolutionaryCSCReducer::setup()
+{
+ if (!canExpand()) return;
+
+ const auto& mapping = m_state.getMapping();
+
+ // Prepare adjacent source vertices
+ m_state.iterateSourceGraphAdjacent(m_sourceVertex, [&](vertex_t adjacentSource){
+ if (mapping.contains(adjacentSource)) m_adjacentSourceVertices.insert(adjacentSource);
+ });
+
+ // Prepare intial "m_adjacentSources" adjacency list
+ for (vertex_t target : m_bestSuperVertex) prepareVertex(target, m_temporary, false);
+
+ m_bestFitness = getFitness(m_bestSuperVertex);
+ initializePopulations();
+}
+
+void EvolutionaryCSCReducer::initializePopulations()
+{
+ m_populationA.resize(POPULATION_SIZE);
+ m_populationB.resize(POPULATION_SIZE);
+
+ for (auto& individual : m_populationA)
+ {
+ individual.initialize(*this, m_sourceVertex);
+ individual.fromInitial(m_bestSuperVertex); // at this point m_bestSuperVertex is initial placement
+ }
+ for (auto& individual : m_populationB)
+ {
+ individual.initialize(*this, m_sourceVertex);
+ }
+}
+
+bool EvolutionaryCSCReducer::canExpand()
+{
+ // Check whether there is some unoccupied adjacent target vertex
+ const auto& targetRemaining = m_state.getRemainingTargetNodes();
+ m_expansionPossible = false;
+ for (vertex_t mappedTarget : m_bestSuperVertex)
+ {
+ m_state.iterateTargetGraphAdjacentBreak(mappedTarget,
+ [&](fuint32_t adjTarget){
+ if (!m_bestSuperVertex.contains(adjTarget) && targetRemaining.contains(adjTarget))
+ {
+ m_expansionPossible = true;
+ }
+ return m_expansionPossible;
+ });
+ if (m_expansionPossible) return true;
+ }
+ return false;
+}
+
+
+void EvolutionaryCSCReducer::optimizeIteration(Vector& parentPopulation)
+{
+ // optimize all in parent population
+ #define MULTITHREADED 1
+ #if MULTITHREADED == 1
+ for (auto& parent : parentPopulation)
+ {
+ m_threadManager.run( [&]() { parent.optimize(); });
+ }
+ m_threadManager.wait();
+ #else
+ for (auto& parent : parentPopulation) parent.optimize();
+ #endif
+ // sort parent population
+ std::sort(parentPopulation.begin(), parentPopulation.end(), std::less());
+
+ size_t newBestFitness = parentPopulation[0].getFitness();
+ size_t size = parentPopulation.at(0).getSolutionSize();
+ if (newBestFitness < m_bestFitness ||
+ (newBestFitness == m_bestFitness && size < m_bestSuperVertex.size()))
+ { // adopt new superior solution
+ m_bestFitness = newBestFitness;
+ m_bestSuperVertex.clear();
+ const auto& newSuperVertex = parentPopulation[0].getSuperVertex();
+ m_bestSuperVertex.insert(newSuperVertex.begin(), newSuperVertex.end());
+ m_improved = true;
+ }
+}
+
+bool EvolutionaryCSCReducer::createNextGeneration(Vector& parentPopulation,
+ Vector& childPopulation)
+{
+ fuint32_t remainingAttemps = 5 * POPULATION_SIZE;
+ for (fuint32_t idx = 3; idx < POPULATION_SIZE && remainingAttemps > 0; --remainingAttemps)
+ {
+ const CSCIndividual* parentA = tournamentSelection(parentPopulation);
+ const CSCIndividual* parentB = tournamentSelection(parentPopulation);
+ bool success = childPopulation[idx].fromCrossover(*parentA, *parentB);
+ if (success) idx++;
+ // else std::cout << "Dead crossover!" << std::endl;
+ }
+ return remainingAttemps > 0;
+}
+
+const CSCIndividual* EvolutionaryCSCReducer::tournamentSelection(const Vector& parentPopulation)
+{
+ fuint32_t max = POPULATION_SIZE - 1;
+
+ const CSCIndividual* individualA = &parentPopulation.at(m_random.getRandomUint(max));
+ const CSCIndividual* individualB = &parentPopulation.at(m_random.getRandomUint(max));
+ return *individualA < *individualB ? individualA : individualB;
+}
+
+
+void EvolutionaryCSCReducer::prepareVertex(vertex_t target, nodeset_t& temp, bool count)
+{
+ if (!m_preparedVertices.contains(target))
+ {
+ temp.clear();
+ m_state.iterateTargetAdjacentReverseMapping(target,
+ [&](vertex_t adjacentSource){
+ if (m_adjacentSourceVertices.contains(adjacentSource)) temp.insert(adjacentSource);
+ });
+ m_state.iterateReverseMapping(target, [&](vertex_t source){
+ if (m_adjacentSourceVertices.contains(source)) temp.insert(source);
+ });
+ }
+
+ m_prepareLock.lock();
+ if (!m_preparedVertices.contains(target))
+ {
+ for (vertex_t source : temp)
+ {
+ m_adjacentSources.insert(std::make_pair(target, source));
+ }
+ const auto& reverse = m_state.getReverseMapping();
+ if (count) m_vertexFitness.insert(std::make_pair(target, reverse.count(target)));
+ m_preparedVertices.insert(target);
+ }
+ m_prepareLock.unlock();
+ temp.clear();
+}
+
+void EvolutionaryCSCReducer::addConnectivity(VertexNumberMap& connectivity, nodeset_t& temp, vertex_t target)
+{
+ if (!m_preparedVertices.contains(target)) prepareVertex(target, temp);
+
+ auto range = m_adjacentSources.equal_range(target);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ connectivity[it->second]++;
+ }
+}
+
+size_t EvolutionaryCSCReducer::getFitness(const nodeset_t& placement) const
+{
+ size_t fitness = 0;
+ VertexNumberMap::const_iterator findIt;
+ for (auto vertex : placement)
+ {
+ findIt = m_vertexFitness.find(vertex);
+ if (findIt != m_vertexFitness.end()) fitness += findIt->second;
+ }
+ return fitness;
+}
+
+size_t EvolutionaryCSCReducer::getFitness(vertex_t target) const
+{
+ auto findIt = m_vertexFitness.find(target);
+ return findIt == m_vertexFitness.end() ? 0 : findIt->second;
+}
+
+bool EvolutionaryCSCReducer::isRemoveable(VertexNumberMap& connectivity, vertex_t target) const
+{
+ auto range = m_adjacentSources.equal_range(target);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ if (connectivity[it->second] <= 1) return false;
+ }
+ return true;
+}
+
+void EvolutionaryCSCReducer::removeVertex(VertexNumberMap& connectivity, vertex_t target) const
+{
+ auto range = m_adjacentSources.equal_range(target);
+ for (auto it = range.first; it != range.second; ++it)
+ {
+ auto findIt = connectivity.find(it->second);
+ if (findIt != connectivity.end()) findIt->second--;
+ }
+}
+
+bool CSCIndividual::isConnected() const
+{
+ for (const auto& connect : m_connectivity)
+ {
+ if (connect.second == 0) return false;
+ }
+ return true;
+}
+
+void CSCIndividual::initialize(EvolutionaryCSCReducer& reducer, vertex_t sourceVertex)
+{
+ m_reducer = &reducer;
+ m_state = &reducer.m_state;
+ m_sourceVertex = sourceVertex;
+ m_random = std::make_unique();
+}
+
+
+
+void CSCIndividual::fromInitial(const nodeset_t& placement)
+{
+ m_done = false;
+ m_superVertex.clear();
+ m_superVertex.insert(placement.begin(), placement.end());
+
+ setupConnectivity();
+}
+
+bool CSCIndividual::fromCrossover(const CSCIndividual& individualA, const CSCIndividual& individualB)
+{
+ m_done = false;
+ m_superVertex.clear();
+ const auto& superVertexA = individualA.getSuperVertex();
+ const auto& superVertexB = individualB.getSuperVertex();
+ // std::cout << "Crossover: overlapping - " << overlappingSets(superVertexA, superVertexB) << "; connected - "
+ // << areSetsConnected(*m_state, superVertexA, superVertexB) << std::endl;
+ if (!overlappingSets(superVertexA, superVertexB)
+ && !areSetsConnected(*m_state, superVertexA, superVertexB))
+ {
+ m_done = true;
+ return false;
+ }
+ m_superVertex.insert(superVertexA.begin(), superVertexA.end());
+ m_superVertex.insert(superVertexB.begin(), superVertexB.end());
+ setupConnectivity();
+ return true;
+}
+
+void CSCIndividual::printConnectivity() const
+{
+ printVertexNumberMap(m_connectivity);
+}
+
+void CSCIndividual::setupConnectivity()
+{
+ const auto& adjacentSourceVertices = m_reducer->getAdjacentSourceVertices();
+ for (auto adjSource : adjacentSourceVertices)
+ {
+ m_connectivity[adjSource] = 0;
+ }
+
+ for (auto target : m_superVertex)
+ {
+ m_reducer->addConnectivity(m_connectivity, m_temporarySet, target);
+ }
+}
+
+void CSCIndividual::optimize()
+{
+ if (m_done) return;
+ CHRONO_STUFF(t1,t2,diff1,TIME_MUTATION, mutate();)
+
+ CHRONO_STUFF(t3,t4,diff2, TIME_REDUCE, reduce();)
+ m_fitness = m_reducer->getFitness(m_superVertex);
+ m_done = true;
+}
+
+
+size_t CSCIndividual::getSolutionSize() const
+{
+ return m_superVertex.size();
+}
+
+size_t CSCIndividual::getFitness() const
+{
+ return m_fitness;
+}
+
+void CSCIndividual::mutate()
+{
+ m_temporarySet.clear();
+ for (vertex_t vertex : m_superVertex)
+ {
+ m_state->iterateFreeTargetAdjacent(vertex,
+ [&](vertex_t adjacentTarget){
+ if(!m_superVertex.contains(adjacentTarget))
+ {
+ m_temporarySet.insert(adjacentTarget);
+ }
+ });
+ }
+ if (m_temporarySet.empty()) return;
+
+ vertex_t startVertex = m_random->getRandomVertex(m_temporarySet);
+
+ if (!isDefined(startVertex)) return;
+ m_temporarySet.clear();
+ clearStack(m_iteratorStack);
+
+ const auto& targetGraph = m_state->getTargetAdjGraph();
+ const auto& remaining = m_state->getRemainingTargetNodes();
+
+ fuint32_t numberAdded = 1;
+ addVertex(startVertex);
+ m_iteratorStack.push(targetGraph.equal_range(startVertex));
+ while(!m_iteratorStack.empty() && numberAdded <= MAX_NEW_VERTICES)
+ {
+ auto& top = m_iteratorStack.top();
+ if (top.first == top.second)
+ {
+ m_iteratorStack.pop();
+ continue;
+ }
+ vertex_t adjacent = top.first->second;
+ if (remaining.contains(adjacent) && !m_superVertex.contains(adjacent))
+ { // add node
+ top.first++;
+ addVertex(adjacent);
+ numberAdded++;
+ m_iteratorStack.push(targetGraph.equal_range(adjacent));
+ }
+ else
+ {
+ top.first++;
+ }
+ }
+}
+
+void CSCIndividual::reduce()
+{
+ if (m_superVertex.size() <= 1) return;
+ m_vertexVector.resize(m_superVertex.size());
+ fuint32_t idx = 0;
+ for (vertex_t vertex : m_superVertex) m_vertexVector[idx++] = vertex;
+ fuint32_t vectorSize = m_vertexVector.size();
+
+ // Try greedily reducing overlap vertices
+ for (idx = 0; idx < vectorSize;)
+ {
+ vertex_t* current = &m_vertexVector[idx];
+ if (m_reducer->getFitness(*current) != 0 && tryRemove(*current))
+ {
+ *current = m_vertexVector.back();
+ m_vertexVector.resize(--vectorSize);
+ }
+ else idx++;
+ }
+
+ // Try reducing all other vertices
+ fuint32_t maxIterations = REDUCE_ITERATION_COEFFICIENT * m_vertexVector.size();
+ vectorSize = m_vertexVector.size();
+ for (fuint32_t iteration = 0; iteration < maxIterations; ++iteration)
+ {
+ fuint32_t randomIdx = m_random->getRandomUint(vectorSize - 1);
+ vertex_t* current = &m_vertexVector[randomIdx];
+ if (!m_superVertex.contains(*current) || tryDfsRemove(*current, iteration))
+ {
+ *current = m_vertexVector.back();
+ m_vertexVector.resize(--vectorSize);
+ }
+ }
+
+ for (idx = 0; idx < vectorSize; ++idx)
+ {
+ if (m_superVertex.contains(m_vertexVector[idx])) tryRemove(m_vertexVector[idx]);
+ }
+}
+
+void CSCIndividual::addVertex(vertex_t target)
+{
+ if (m_superVertex.contains(target)) return;
+ m_reducer->addConnectivity(m_connectivity, m_temporarySet, target);
+ m_superVertex.insert(target);
+}
+
+bool CSCIndividual::tryRemove(vertex_t target)
+{
+ // Remove if not a cut vertex
+ if (!m_reducer->isRemoveable(m_connectivity, target)) return false;
+
+ m_temporarySet.clear();
+ m_temporarySet.insert(m_superVertex.begin(), m_superVertex.end());
+ if (!isCutVertex(*m_state, m_temporarySet, target))
+ {
+ m_reducer->removeVertex(m_connectivity, target);
+ m_superVertex.unsafe_erase(target);
+ return true;
+ }
+ m_temporarySet.clear();
+ return false;
+}
+
+bool CSCIndividual::tryDfsRemove(vertex_t target, fuint32_t& iteration)
+{
+ if (!tryRemove(target)) return false;
+
+ const auto& targetGraph = m_state->getTargetAdjGraph();
+ clearStack(m_iteratorStack);
+ m_iteratorStack.push(targetGraph.equal_range(target));
+ while(!m_iteratorStack.empty())
+ {
+ auto& top = m_iteratorStack.top();
+ if (top.first == top.second) m_iteratorStack.pop();
+ else if (m_superVertex.contains(top.first->second))
+ {
+ vertex_t adjacent = top.first->second;
+ top.first++;
+ iteration++;
+ bool success = tryRemove(adjacent);
+ if (success) m_iteratorStack.push(targetGraph.equal_range(adjacent));
+ }
+ else top.first++;
+ }
+ return true;
+}
+
diff --git a/src/initial/csc_evolutionary.hpp b/src/initial/csc_evolutionary.hpp
new file mode 100644
index 0000000..5e32054
--- /dev/null
+++ b/src/initial/csc_evolutionary.hpp
@@ -0,0 +1,120 @@
+#ifndef __MAJORMINER_CSC_EVOLUTIONARY_HPP_
+#define __MAJORMINER_CSC_EVOLUTIONARY_HPP_
+
+#include
+#include
+
+namespace majorminer
+{
+
+ class CSCIndividual
+ {
+ friend EvolutionaryCSCReducer;
+ public:
+ CSCIndividual(): m_reducer(nullptr), m_done(false) {}
+
+ void initialize(EvolutionaryCSCReducer& reducer, vertex_t sourceVertex);
+
+ void fromInitial(const nodeset_t& placement);
+ bool fromCrossover(const CSCIndividual& individualA, const CSCIndividual& individualB);
+ void optimize();
+ const nodeset_t& getSuperVertex() const { return m_superVertex; }
+ bool isConnected() const;
+ void printConnectivity() const;
+
+ private:
+ void addVertex(vertex_t target);
+ bool tryRemove(vertex_t target);
+ bool tryDfsRemove(vertex_t target, fuint32_t& iteration);
+ void mutate();
+ void reduce();
+ void setupConnectivity();
+ size_t getSolutionSize() const;
+ size_t getFitness() const;
+
+ public:
+ friend bool operator<(const CSCIndividual& in1, const CSCIndividual& in2)
+ {
+ return in1.getFitness() < in2.getFitness()
+ || (in1.getFitness() == in2.getFitness() && in1.getSolutionSize() < in2.getSolutionSize());
+ }
+
+ private:
+ EvolutionaryCSCReducer* m_reducer;
+ const EmbeddingState* m_state;
+ vertex_t m_sourceVertex;
+ nodeset_t m_superVertex;
+ VertexNumberMap m_connectivity;
+ size_t m_fitness;
+
+ nodeset_t m_temporarySet;
+ Stack m_iteratorStack;
+ Vector m_vertexVector;
+ std::unique_ptr m_random;
+
+ bool m_done;
+ };
+
+ class EvolutionaryCSCReducer
+ {
+ friend CSCIndividual;
+ public:
+ EvolutionaryCSCReducer(EmbeddingState& state, vertex_t sourceVertex);
+ EvolutionaryCSCReducer(EmbeddingState& state, const nodeset_t& initial, vertex_t sourceVertex);
+
+ void setVisualizer(EmbeddingVisualizer* vis) { m_visualizer = vis; }
+ void optimize();
+ const nodeset_t& getPlacement() const { return m_bestSuperVertex; }
+ bool foundBetter() const { return m_improved; }
+
+ private:
+ void initialize();
+ void initialize(const nodeset_t& initial);
+ void setup();
+ bool canExpand();
+ void initializePopulations();
+ void optimizeIteration(Vector& parentPopulation);
+ bool createNextGeneration(Vector& parentPopulation, Vector& childPopulation);
+ void prepareVertex(vertex_t target, nodeset_t& temp, bool count = true);
+ const CSCIndividual* tournamentSelection(const Vector& parentPopulation);
+ void visualize(fuint32_t iteration, Vector* population);
+
+ private: // called mainly by CSCIndividual
+ void addConnectivity(VertexNumberMap& connectivity, nodeset_t& temp, vertex_t target);
+ bool isRemoveable(VertexNumberMap& connectivity, vertex_t target) const;
+ void removeVertex(VertexNumberMap& connectivity, vertex_t target) const;
+ size_t getFitness(vertex_t target) const;
+ size_t getFitness(const nodeset_t& placement) const;
+ const nodeset_t& getAdjacentSourceVertices() const { return m_adjacentSourceVertices; }
+
+ private:
+ const EmbeddingState& m_state;
+ vertex_t m_sourceVertex;
+ bool m_wasPlaced;
+ bool m_expansionPossible;
+ bool m_improved;
+
+ EmbeddingVisualizer* m_visualizer;
+ ThreadManager& m_threadManager;
+
+ Vector m_populationA;
+ Vector m_populationB;
+ adjacency_list_t m_adjacentSources;
+ nodeset_t m_adjacentSourceVertices;
+ VertexNumberMap m_vertexFitness;
+ nodeset_t m_preparedVertices;
+
+ nodeset_t m_bestSuperVertex;
+ size_t m_bestFitness;
+
+ nodeset_t m_temporary;
+ RandomGen m_random;
+
+ std::mutex m_prepareLock;
+ };
+
+}
+
+
+
+#endif
\ No newline at end of file
diff --git a/src/initial/network_simplex.cpp b/src/initial/network_simplex.cpp
index fbd451d..1cdf467 100644
--- a/src/initial/network_simplex.cpp
+++ b/src/initial/network_simplex.cpp
@@ -1,4 +1,9 @@
-#include "network_simplex.hpp"
+#include "initial/network_simplex.hpp"
+
+#include
+#include
+#include
+#include
using namespace majorminer;
@@ -6,99 +11,161 @@ using namespace majorminer;
#define OCCUPIED 10
#define FREE 1
-void NetworkSimplexWrapper::embeddNode(fuint32_t node)
+
+NetworkSimplexWrapper::NetworkSimplexWrapper(EmbeddingState& state, EmbeddingManager& embeddingManager)
+ : m_state(state), m_embeddingManager(embeddingManager), m_initialized(false)
+{ }
+
+NetworkSimplexWrapper::capacity_t NetworkSimplexWrapper::getNumberAdjacentNodes(const adjacency_list_range_iterator_t& adjacentIt) const
{
- auto adjacentIt = m_suite->m_source.equal_range(node);
- clear();
+ const auto& mapping = m_state.getMapping();
capacity_t n = 0;
for (auto adjacentNode = adjacentIt.first; adjacentNode != adjacentIt.second; ++adjacentNode)
{
- if (m_suite->m_mapping.find(adjacentNode->second) != m_suite->m_mapping.end()) n++;
+ if (mapping.contains(adjacentNode->second)) n++;
}
- if (n < 2) throw std::runtime_error("Invalid number of embedded adjacent nodes! < 2...");
- auto lowered = n - 1;
- // DEBUG(OUT_S << "Flow of " << lowered << " needed." << std::endl;)
-
- LemonArcMap costs(m_graph);
- LemonArcMap caps(m_graph);
+ // if (n < 2) throw std::runtime_error("Invalid number of embedded adjacent nodes! < 2...");
+ return n;
+}
- for (const auto& arc : *(m_suite->m_targetGraph))
+void NetworkSimplexWrapper::constructLemonGraph()
+{
+ // Construct base graph
+ const auto& targetGraph = *m_state.getTargetGraph();
+ for (const auto& arc : targetGraph)
{
auto uNode = createNode(arc.first);
auto vNode = createNode(arc.second);
LemonArc uv = m_graph.addArc(uNode, vNode);
LemonArc vu = m_graph.addArc(vNode, uNode);
m_edgeMap.insert(std::make_pair(arc, std::make_pair(uv, vu)));
- caps[uv] = lowered;
- caps[vu] = lowered;
- costs[uv] = determineCost(arc.first);
- costs[vu] = determineCost(arc.second);
}
+}
+
+vertex_t NetworkSimplexWrapper::chooseSource(vertex_t source) const
+{
+ vertex_t bestFound = FUINT32_UNDEF;
+ m_state.iterateSourceMappingAdjacent(source,
+ [&](vertex_t adjacent, vertex_t){
+ bestFound = adjacent;
+ return true;
+ });
+ if (isDefined(bestFound)) return bestFound;
+
+ const auto& reverse = m_state.getReverseMapping();
+ const auto& remaining = m_state.getRemainingTargetNodes();
+ fuint32_t numberMapped = FUINT32_UNDEF;
+
+ m_state.iterateSourceMappingAdjacent(source,
+ [&](vertex_t adjacent, vertex_t){
+ if (remaining.contains(adjacent)) return false;
+ fuint32_t nb = reverse.count(adjacent);
+ if (nb < numberMapped)
+ {
+ numberMapped = nb;
+ bestFound = adjacent;
+ }
+ return numberMapped == 1; // we can skip if we find a vertex
+ });
+ if (!isDefined(bestFound)) throw std::runtime_error("Isolated vertex in network simplex!");
+ return bestFound;
+}
+
+NetworkSimplexWrapper::LemonNode& NetworkSimplexWrapper::getNextRootNode()
+{
+ if (m_rootCounter < m_rootVertices.size()) return m_rootVertices[m_rootCounter++];
+ else
+ {
+ m_rootVertices.push_back(m_graph.addNode());
+ LemonNode& root = m_rootVertices.back();
+ createCheapArc(root, m_t, *m_costMap, *m_capMap, false);
+ m_rootCounter++;
+ return root;
+ }
+}
+
+void NetworkSimplexWrapper::createCheapArc(LemonNode& from, LemonNode& to,
+ LemonArcMap& costs, LemonArcMap& caps, bool constructionArc, capacity_t capacity)
+{
+ auto temp = m_graph.addArc(from, to);
+ costs[temp] = 0;
+ caps[temp] = capacity;
+ if (constructionArc) m_treeConstructionArcs.push_back(temp);
+}
- LemonNode s = m_graph.addNode();
- LemonNode t = m_graph.addNode();
+void NetworkSimplexWrapper::constructHelperNodes(LemonArcMap& costs, LemonArcMap& caps,
+ const adjacency_list_range_iterator_t& adjacentIt)
+{
// define nodes for construction
- bool first = true;
- fuint32_t sConnected = -1;
+ const auto& mapping = m_state.getMapping();
+
+ vertex_t adjacentCandidate = FUINT32_UNDEF;
+
+ // sink vertices
for (auto adjacentNode = adjacentIt.first; adjacentNode != adjacentIt.second; ++adjacentNode)
{
- auto embeddingPath = m_suite->m_mapping.equal_range(adjacentNode->second);
+ auto embeddingPath = mapping.equal_range(adjacentNode->second);
if (embeddingPath.first == embeddingPath.second) continue;
- if (first)
- { // define s node connection
- auto toNode = m_nodeMap[embeddingPath.first->second];
- sConnected = embeddingPath.first->second;
- auto arc = m_graph.addArc(s, toNode);
- costs[arc] = 0;
- caps[arc] = lowered;
- first = false;
- adjustCosts(embeddingPath.first->second, costs);
- continue;
- }
- // DEBUG(OUT_S << "Adding construction for node " << adjacentNode->second << std::endl;)
- LemonNode constructionNode = m_graph.addNode();
- auto out = m_graph.addArc(constructionNode, t);
- costs[out] = 0;
- caps[out] = 1;
+ adjacentCandidate = adjacentNode->second;
+
+ LemonNode& constructionNode = getNextRootNode();
for (auto targetNode = embeddingPath.first; targetNode != embeddingPath.second; ++targetNode)
{
LemonNode& fromNode = m_nodeMap[targetNode->second];
- auto temp = m_graph.addArc(fromNode, constructionNode);
- costs[temp] = 0;
- caps[temp] = 1;
+ createCheapArc(fromNode, constructionNode, costs, caps, true);
}
}
+ // source vertex
+ vertex_t sVertex = chooseSource(adjacentCandidate);
+ LemonNode& toNode = m_nodeMap[sVertex];
+ m_sConnected = sVertex;
+ createCheapArc(m_s, toNode, costs, caps, true, m_numberAdjacent);
+ //adjustCosts(sVertex, costs);
+}
+
+void NetworkSimplexWrapper::initialCreation()
+{
+ m_costMap = std::make_unique>(m_graph);
+ m_capMap = std::make_unique>(m_graph);
+ m_flowMap = std::make_unique>(m_graph);
+ constructLemonGraph();
+ m_s = m_graph.addNode();
+ m_t = m_graph.addNode();
+ m_initialized = true;
+}
+
+void NetworkSimplexWrapper::embeddNode(vertex_t node)
+{
+ if (!m_initialized) initialCreation();
+ clear();
+ auto adjacentIt = m_state.getSourceAdjGraph().equal_range(node);
+ m_numberAdjacent = getNumberAdjacentNodes(adjacentIt);
+
+ setupCostsAndCaps();
+
+ constructHelperNodes(*m_costMap, *m_capMap, adjacentIt);
NetworkSimplex ns(m_graph);
- ns.costMap(costs).upperMap(caps).stSupply(s, t, lowered);
- LemonArcMap flows(m_graph);
+ ns.costMap(*m_costMap).upperMap(*m_capMap).stSupply(m_s, m_t, m_numberAdjacent);
NetworkSimplex::ProblemType status = ns.run();
if (status == NetworkSimplex::OPTIMAL)
{
- LemonArcMap flows{m_graph};
+ LemonArcMap& flows = *m_flowMap;
ns.flowMap(flows);
- fuint32_t nbOutFlows = 0;
for (const auto& arc : m_edgeMap)
{
- // DEBUG(OUT_S << "(" << arc.first.first << "," << arc.first.second << "): " << flows[arc.second.first] << std::endl;)
- // DEBUG(OUT_S << "(" << arc.first.second << "," << arc.first.first << "): " << flows[arc.second.second] << std::endl;)
if (flows[arc.second.first] > 0)
{
m_mapped.insert(arc.first.first);
- if (arc.first.first == sConnected) nbOutFlows++;
}
if (flows[arc.second.second] > 0)
{
- if (arc.first.second == sConnected) nbOutFlows++;
m_mapped.insert(arc.first.second);
}
}
- OUT_S << "Number outflows " << nbOutFlows << std::endl;
- if (nbOutFlows < 2 && m_mapped.size() > 1) m_mapped.unsafe_erase(sConnected);
- m_suite->mapNode(node, m_mapped);
}
else if(status == NetworkSimplex::INFEASIBLE)
{
@@ -111,13 +178,14 @@ void NetworkSimplexWrapper::embeddNode(fuint32_t node)
}
-void NetworkSimplexWrapper::adjustCosts(fuint32_t node, LemonArcMap& costs)
+void NetworkSimplexWrapper::adjustCosts(vertex_t node, LemonArcMap& costs)
{
- auto adjacentIt = m_suite->m_target.equal_range(node);
+ auto adjacentIt = m_state.getTargetAdjGraph().equal_range(node);
+ const auto& targetNodesRemaining = m_state.getRemainingTargetNodes();
for (auto it = adjacentIt.first; it != adjacentIt.second; ++it)
{
const auto& edges = getArcPair(node, it->second);
- if (m_suite->m_targetNodesRemaining.contains(it->second))
+ if (targetNodesRemaining.contains(it->second))
{
costs[edges.first] = FREE;
costs[edges.second] = FREE;
@@ -129,7 +197,7 @@ void NetworkSimplexWrapper::adjustCosts(fuint32_t node, LemonArcMap& cos
}
}
}
-const NetworkSimplexWrapper::LemonArcPair& NetworkSimplexWrapper::getArcPair(fuint32_t n1, fuint32_t n2)
+const NetworkSimplexWrapper::LemonArcPair& NetworkSimplexWrapper::getArcPair(vertex_t n1, vertex_t n2)
{
auto findIt = m_edgeMap.find(edge_t{n1, n2});
if (findIt != m_edgeMap.end())
@@ -139,27 +207,45 @@ const NetworkSimplexWrapper::LemonArcPair& NetworkSimplexWrapper::getArcPair(fui
return m_edgeMap[edge_t{n2, n1}];
}
-NetworkSimplexWrapper::LemonNode NetworkSimplexWrapper::createNode(fuint32_t node)
+NetworkSimplexWrapper::LemonNode NetworkSimplexWrapper::createNode(vertex_t node)
{
auto findIt = m_nodeMap.find(node);
if (findIt == m_nodeMap.end())
{
- m_nodeMap.insert(std::make_pair(node, m_graph.addNode()));
- return m_nodeMap[node];
+ auto it = m_nodeMap.insert(std::make_pair(node, m_graph.addNode()));
+ return it.first->second;
}
return findIt->second;
}
-NetworkSimplexWrapper::cost_t NetworkSimplexWrapper::determineCost(fuint32_t node)
+NetworkSimplexWrapper::cost_t NetworkSimplexWrapper::determineCost(vertex_t node)
{
- if (m_suite->m_nodesOccupied.contains(node)) return OCCUPIED;
- return FREE;
+ return m_state.isNodeOccupied(node) ? OCCUPIED : FREE;
+}
+
+void NetworkSimplexWrapper::setupCostsAndCaps()
+{
+ // set all costs of nonartificial arcs
+ for (const auto& edgePair : m_edgeMap)
+ {
+ const auto& uv = edgePair.second.first;
+ const auto& vu = edgePair.second.second;
+ (*m_capMap)[uv] = m_numberAdjacent;
+ (*m_capMap)[vu] = m_numberAdjacent;
+ (*m_costMap)[uv] = determineCost(edgePair.first.first);
+ (*m_costMap)[vu] = determineCost(edgePair.first.second);
+ }
}
void NetworkSimplexWrapper::clear()
{
- m_graph.clear();
- m_nodeMap.clear();
+ for (auto& lemonArc : m_treeConstructionArcs)
+ {
+ (*m_capMap)[lemonArc] = 0;
+ }
m_mapped.clear();
- m_edgeMap.clear();
+ m_numberAdjacent = 0;
+ m_sConnected = -1;
+
+ m_rootCounter = 0;
}
diff --git a/src/initial/network_simplex.hpp b/src/initial/network_simplex.hpp
index 61b88be..fe066ce 100644
--- a/src/initial/network_simplex.hpp
+++ b/src/initial/network_simplex.hpp
@@ -4,13 +4,10 @@
#include
#include
-#include "majorminer_types.hpp"
-#include "majorminer.hpp"
+#include
namespace majorminer
{
- class EmbeddingSuite;
-
class NetworkSimplexWrapper
{
using cost_t = int;
@@ -22,25 +19,58 @@ namespace majorminer
using LemonArcMap = LemonGraph::ArcMap;
using NetworkSimplex = lemon::NetworkSimplex;
typedef std::pair LemonArcPair;
+
public:
- NetworkSimplexWrapper(EmbeddingSuite* suite)
- : m_suite(suite) { }
+ NetworkSimplexWrapper(EmbeddingState& state, EmbeddingManager& embeddingManager);
- void embeddNode(fuint32_t node);
+ void embeddNode(vertex_t node);
+ const nodeset_t& getMapped() const { return m_mapped; }
private:
- LemonNode createNode(fuint32_t node);
- cost_t determineCost(fuint32_t node);
- void adjustCosts(fuint32_t node, LemonArcMap& costs);
+ void initialCreation();
+ LemonNode createNode(vertex_t node);
+ cost_t determineCost(vertex_t node);
+ void adjustCosts(vertex_t node, LemonArcMap& costs);
+ void setupCostsAndCaps();
+
+ const LemonArcPair& getArcPair(vertex_t n1, vertex_t n2);
+ vertex_t chooseSource(vertex_t source) const;
+
+ void createCheapArc(LemonNode& from, LemonNode& to, LemonArcMap& costs,
+
+ LemonArcMap& caps, bool constructionArc = false, capacity_t capacity = 1);
+
+ capacity_t getNumberAdjacentNodes(const adjacency_list_range_iterator_t& adjacentIt) const;
+ void constructLemonGraph();
+ void constructHelperNodes(LemonArcMap& costs, LemonArcMap& caps,
+ const adjacency_list_range_iterator_t& adjacentIt);
+
+ LemonNode& getNextRootNode();
void clear();
- const LemonArcPair& getArcPair(fuint32_t n1, fuint32_t n2);
private:
LemonGraph m_graph;
- EmbeddingSuite* m_suite;
- UnorderedMap m_nodeMap;
- UnorderedMap> m_edgeMap;
- UnorderedSet m_mapped;
+ EmbeddingState& m_state;
+ EmbeddingManager& m_embeddingManager;
+ UnorderedMap m_nodeMap;
+ UnorderedMap> m_edgeMap;
+ UnorderedSet m_mapped;
+
+ std::unique_ptr> m_costMap;
+ std::unique_ptr> m_capMap;
+ std::unique_ptr> m_flowMap;
+
+ Vector m_rootVertices;
+ Vector m_treeConstructionArcs;
+
+ LemonNode m_s;
+ LemonNode m_t;
+
+ capacity_t m_numberAdjacent;
+ fuint32_t m_sConnected;
+ fuint32_t m_rootCounter;
+
+ bool m_initialized;
};
}
diff --git a/src/initial/super_vertex_placer.cpp b/src/initial/super_vertex_placer.cpp
new file mode 100644
index 0000000..9ccc9e4
--- /dev/null
+++ b/src/initial/super_vertex_placer.cpp
@@ -0,0 +1,247 @@
+#include "super_vertex_placer.hpp"
+
+#include "super_vertex_reducer.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include