diff --git a/.gitignore b/.gitignore index 9b4ea58..9f6e045 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -results/ +4results/ Backup_results/ # Byte-compiled / optimized / DLL files __pycache__/ @@ -52,6 +52,7 @@ coverage.xml *.cover .hypothesis/ .pytest_cache/ +temp.py # Translations *.mo @@ -70,7 +71,7 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +# _build # PyBuilder target/ @@ -125,4 +126,16 @@ dmypy.json # Pyre type checker .pyre/ -*.json \ No newline at end of file +*.json + +# vsCode settings +.vscode/ + +# Pycharm files +.idea/ + +*.csv + +# Graphviz files +*.gv +*.gv.png diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 92a2fa2..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Current File (Integrated Terminal)", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "integratedTerminal" - }, - { - "name": "Python: Remote Attach", - "type": "python", - "request": "attach", - "port": 5678, - "host": "localhost", - "pathMappings": [ - { - "localRoot": "${workspaceFolder}", - "remoteRoot": "." - } - ] - }, - { - "name": "Python: Module", - "type": "python", - "request": "launch", - "module": "enter-your-module-name-here", - "console": "integratedTerminal" - }, - { - "name": "Python: Django", - "type": "python", - "request": "launch", - "program": "${workspaceFolder}/manage.py", - "console": "integratedTerminal", - "args": [ - "runserver", - "--noreload", - "--nothreading" - ], - "django": true - }, - { - "name": "Python: Flask", - "type": "python", - "request": "launch", - "module": "flask", - "env": { - "FLASK_APP": "app.py" - }, - "args": [ - "run", - "--no-debugger", - "--no-reload" - ], - "jinja": true - }, - { - "name": "Python: Current File (External Terminal)", - "type": "python", - "request": "launch", - "program": "${file}", - "console": "externalTerminal" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 36cfe4d..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "python.pythonPath": "/home/bhupinder/.virtualenvs/pyRVEA/bin/python", - "python.linting.flake8Enabled": true, - "python.linting.mypyEnabled": false, - "python.linting.enabled": true, - "python.linting.pylintEnabled": false -} \ No newline at end of file diff --git a/Example.py b/Example.py index ef66c06..c52ca49 100644 --- a/Example.py +++ b/Example.py @@ -4,13 +4,15 @@ Visit the github/binder page for further information. """ from pyrvea.Population.Population import Population -from pyrvea.Problem.baseProblem import baseProblem +from pyrvea.Problem.baseproblem import BaseProblem +from pyrvea.EAs.PPGA import PPGA from pyrvea.EAs.RVEA import RVEA +from pyrvea.EAs.slowRVEA import slowRVEA from pyrvea.EAs.NSGAIII import NSGAIII from optproblems import dtlz -class newProblem(baseProblem): +class newProblem(BaseProblem): """New problem description.""" def objectives(self, decision_variables): @@ -29,9 +31,13 @@ def objectives(self, decision_variables): lattice_resolution = 4 population_size = 105 -pop = Population(problem) +pop = Population( + problem, + crossover_type="simulated_binary_crossover", + mutation_type="bounded_polynomial_mutation", +) -pop.evolve(NSGAIII) +pop.evolve(RVEA) pop.non_dominated() refpoint = 2 diff --git a/Tests/EvoNNModel_ppga_ZDT1_1000pareto.png b/Tests/EvoNNModel_ppga_ZDT1_1000pareto.png new file mode 100644 index 0000000..35d0ebb Binary files /dev/null and b/Tests/EvoNNModel_ppga_ZDT1_1000pareto.png differ diff --git a/Tests/EvoNNModel_rvea_ZDT1_1000pareto.png b/Tests/EvoNNModel_rvea_ZDT1_1000pareto.png new file mode 100644 index 0000000..01ce652 Binary files /dev/null and b/Tests/EvoNNModel_rvea_ZDT1_1000pareto.png differ diff --git a/Tests/PPGAEvoNNModelZDT1_1000f1.png b/Tests/PPGAEvoNNModelZDT1_1000f1.png new file mode 100644 index 0000000..3391a14 Binary files /dev/null and b/Tests/PPGAEvoNNModelZDT1_1000f1.png differ diff --git a/Tests/PPGAEvoNNModelZDT1_1000f2.png b/Tests/PPGAEvoNNModelZDT1_1000f2.png new file mode 100644 index 0000000..5d9c00f Binary files /dev/null and b/Tests/PPGAEvoNNModelZDT1_1000f2.png differ diff --git a/Tests/ZDT1_1000.xls b/Tests/ZDT1_1000.xls new file mode 100644 index 0000000..598bc47 Binary files /dev/null and b/Tests/ZDT1_1000.xls differ diff --git a/ZDT1_1000.xls b/ZDT1_1000.xls new file mode 100644 index 0000000..598bc47 Binary files /dev/null and b/ZDT1_1000.xls differ diff --git a/biogp.png b/biogp.png new file mode 100644 index 0000000..ce22ca0 Binary files /dev/null and b/biogp.png differ diff --git a/docs/.nojekyll b/docs/.nojekyll deleted file mode 100644 index e69de29..0000000 diff --git a/docs/Makefile b/docs/Makefile index 298ea9e..d4bb2cb 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,9 +1,10 @@ # Minimal makefile for Sphinx documentation # -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build @@ -16,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 120000 index 32d46ee..0000000 --- a/docs/README.md +++ /dev/null @@ -1 +0,0 @@ -../README.md \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..42d0fbf --- /dev/null +++ b/docs/README.md @@ -0,0 +1,103 @@ +# Evolutionary algorithms in pyRVEA + +- [EvoNN](#what-is-evonn) +- [EvoDN2](#what-is-evodn2) +- [BioGP](#what-is-biogp) +- [PPGA](#what-is-ppga) +- [Notes](#notes) +- [References](#references) + +## Introduction +The engineering and scientific data that one receives from experiments or simulations from any industry is often very noisy, one needs to have a model to process them effectively. It is, however, very difficult to build a model which captures only the correct trends in the data while devoid of any implicit noise. The models can easily be overfitted so that they capture every fluctuation in the data set, both significant and noisy, or underfitted where some major trends may remain undetected or unrepresented. + +Evolutionary neural networks and genetic programming have succesfully been utilized to come around this problem and create balanced models. Thus, the purpose of these models is not to achieve the tightest fit, or the lowest training error, but to construct models that capture the correct trends in the data, while avoiding the problems of overfitting and underfitting. + +Neural networks and genetic programming have efficiently been utilized for these purposes. This project introduces Python implementations of three evolutionary algrorithms, [EvoNN](#what-is-evonn), [EvoDN2](#what-is-evodn2) and [BioGP](#what-is-biogp). The models can be trained and optimized using the genetic algorithms available in pyRVEA. A predator-prey genetic algorithm ([PPGA](#what-is-ppga)) was also implemented in Python for this project. The user can choose to train and optimize the models with the existing reference vector (RVEA) algorithms, or using the PPGA. + +These algorithms use a concept of an optimal tradeoff between two objectives, leading to a [Pareto frontier](https://en.wikipedia.org/wiki/Pareto_efficiency#Pareto_frontier). When there are conflicting requirements in a problem, it essentially leads to a situation where none of the objectives would be able to attain their individual best. The Pareto frontier consists of solutions where the optima are contained in a set of best possible tradeoffs between the objectives. + +## What is EvoNN? +In **Evo**lutionary **N**eural **N**etwork [[1]](#1) [[2]](#2), the population consists of feed-forward neural networks. Each network consists of an input layer, a hidden layer and an output layer. The data is fed to the networks via input nodes, which pass the information to a hidden layer, where each active connection receives a nonzero weight. The number of connections increases the complexity of the model. The hidden layer also includes a bias term. Then through a transfer function the hidden layer passes the values onwards to the next level where the weights are optimized and passed to the final output of the network. + +![EvoNN](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/evonn.png "An example EvoNN model") + +*Figure 1. An example EvoNN model. [[7]](#7)* + +The evolution happens in the lower part of the network (i.e. between the input layer and the hidden layer), where the weights are optimized using a genetic algorithm (see available [algorithms](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html) in pyRVEA). The two objectives to optimize here are the model's accuracy and complexity. Thus, both the training error and the complexity need to be minimized. The weights are altered using crossover and mutation operations. The upper part of the network is then optimized using a Linear Least Square (LLSQ) approach, which ensures the mathematical convergence to the Pareto front. The evolutionary algorithm then chooses the fittest of the individuals (the ones with the best tradeoff between accuracy and complexity) to go on to the next generation. + +## What is EvoDN2? +**Evo**lutionary **D**eep Neural **N**etwork [[3]](#3) is an extension to EvoNN using deep neural networks and has the capacity for deep learning. The principle of EvoDN2 is the same as EvoNN, but the structure of the networks is different. In EvoDN2, each network consists of multiple subnets, which take in subsets of the input variables so that each variable is used at least once. The subnets have an input layer and multiple hidden layers, and they are optimized just as EvoNN using a genetic algorithm. Finally, the subnets converge on a linear layer, optimized by LLSQ and are mapped to an output. Each subnet has a randomized number of layers and nodes on each layers based on the bounds set by the user. The number of subnets can also be set. + +![EvoDN2](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/evodn.png "An example EvoDN2 model") + +*Figure 2. An example EvoDN2 model. [[3]](#3)* + +The advantage of EvoDN2 over EvoNN is that it fares much better with larger data sets, which can have thousands of data points. With smaller data sets EvoDN2 performs similarly to EvoNN, although EvoDN2 models tend to have a tighter fit. + +The complexity calculation of EvoDN2 is also different from EvoNN. With EvoDN2, the complexity is calculated as the product function of all weight matrices within a subnet, and these weights are the summed together to get the total complexity of the model. This way the connections with a larger magnitude of weight values contribute more to the final value, and inactive connections will be discounted. + +## What is BioGP? +BioGP [[4]](#4) is a **Bi**-**o**bjective **g**enetic **p**rogramming technique, which similarly to EvoNN and EvoDN2 minimizes the model's training error and complexity using genetic algorithms. Whereas many conventional GP algorithms tend to only focus on minimizing the error, one advantage of BioGP is that by calculating the best possibly tradeoff between the error and the complexity, overfitting and underfitting can be addressed. BioGP is designed so that for the first number of generations, it minimizes the training error, after which it switches to bi-objective mode minimizing both error and complexity. + +The benefit of genetic programming in general is the flexibility of allowing the user to select the mathematical operations (function set and terminal set) involved in building the model. BioGP is also designed to combat bloat, where the models may grow larger and larger in size without increasing the fitness. + +The BioGP models are represented with a tree encoding. GP achieves its learning by utilizing a function set containing user-defined mathematical operations like division or square root, and a terminal set containing the variables and the constants. The advantage of GP is that it does not require any pre-defined configuration of weights, biases and transfer functions and thus, it can evolve any mathematical function representing the system being modeled. + +The BioGP tree has a linear node at the top (code-wise, the linear node is at depth=0), from which a number of subtrees emerge. Each of these subtrees represent a nonlinear function, consisting of function nodes and terminal nodes. The linear node takes a weighted sum of the outputs of the subtrees, adds a bias value, and optimizes the weights using LLSQ to calculate the final output of the tree. To handle bloat, BioGP uses a parameter called error reduction ratio which provides a simple quantification of the contribution that a single subtree makes toward the performance of the model. If the contribution is less than the limit set by the user, that subtree is terminated and a new one is grown in its place. + +![BioGP](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/biogp.png "An example BioGP model") + + +*Figure 3. An example BioGP tree. [[4]](#4)* + +The complexity of the model depends on the number of function nodes in the tree, and the tree's total depth. A scalar parameter is used in the complexity function allowing the user to control whether the depth or the number of function nodes should weigh more in the calculation. + +## What is PPGA? +**P**redatory-**P**rey **G**enetic **A**lgorithm [[5]](#5) [[6]](#6) + +A population of prey signify the various models or solutions to the problem at hand. Weaker prey, i.e. bad models or solutions, are killed by predators. The predators and prey are placed in a lattice, in which they are free to roam. + +In each generation, each predator gets a certain number of turns to move about and hunt in its neighbourhood, killing the weaker prey, according to a fitness criteria. After this, each prey gets a certain number of moves to pursue a random walk and to reproduce with other prey. Each reproduction step generates two new prey from two parents, by crossing over their attributes and adding random mutations. After each prey has completed its move, the whole process starts again. + +As the weaker individuals get eliminated in each generation, the population as a whole becomes more fit, i.e. the individuals get closer to the true pareto-optimal solutions. + +## Notes + +The algorithms presented here have been created earlier in MATLAB, and these Python implementations have been using that code as a basis. Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + +The source code of pyRVEA is implemented by Bhupinder Saini. + +## Contact + +If you have any questions about the code, please contact: + +Bhupinder Saini: bhupinder.s.saini@jyu.fi + +Project researcher at University of Jyväskylä. + +Rissanen Niko: nijosari@student.jyu.fi + +Research assistant at University of Jyväskylä. + +## References + +#### 1 +Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham. + +#### 2 +Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397. + +#### 3 +Swagata R., Bhupinder S., Chakrabarti, N. and Chakraborti, N. (2019). A new Deep Neural Network algorithm employed in the study of mechanical properties of micro-alloyed steel. Department of Metallurgical and Materials Engineering, Indian Institute of Technology. + +#### 4 +Giri, B. K., Hakanen, J., Miettinen, K., & Chakraborti, N. (2013). Genetic programming through bi-objective genetic algorithms with a study of a simulated moving bed process involving multiple objectives. Applied Soft Computing, 13(5), 2613-2623. + +#### 5 +Laumanns, M., Rudolph, G., & Schwefel, H. P. (1998). A spatial predator-prey approach to multi-objective optimization: A preliminary study. In International Conference on Parallel Problem Solving from Nature (pp. 241-249). Springer, Berlin, Heidelberg. + +#### 6 +Li, X. (2003). A real-coded predator-prey genetic algorithm for multiobjective optimization. In International Conference on Evolutionary Multi-Criterion Optimization (pp. 207-221). Springer, Berlin, Heidelberg. + +#### 7 +Bhupinder S. Optimization of Vanadium Microalloyed Steel Composition Using Evolutionary Deep Learning Techniques. Master's thesis. Department of Metallurgical and Materials Engineering, Indian Institute of Technology. diff --git a/docs/_build/doctrees/README.doctree b/docs/_build/doctrees/README.doctree index 755d46a..1d259ae 100644 Binary files a/docs/_build/doctrees/README.doctree and b/docs/_build/doctrees/README.doctree differ diff --git a/docs/_build/doctrees/creating_models_example.doctree b/docs/_build/doctrees/creating_models_example.doctree new file mode 100644 index 0000000..eb24e7a Binary files /dev/null and b/docs/_build/doctrees/creating_models_example.doctree differ diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle index ab11128..f726f7a 100644 Binary files a/docs/_build/doctrees/environment.pickle and b/docs/_build/doctrees/environment.pickle differ diff --git a/docs/_build/doctrees/index.doctree b/docs/_build/doctrees/index.doctree index f529cf3..3f9c3d7 100644 Binary files a/docs/_build/doctrees/index.doctree and b/docs/_build/doctrees/index.doctree differ diff --git a/docs/_build/doctrees/pyRVEA.doctree b/docs/_build/doctrees/modules.doctree similarity index 54% rename from docs/_build/doctrees/pyRVEA.doctree rename to docs/_build/doctrees/modules.doctree index 316426f..5843e2d 100644 Binary files a/docs/_build/doctrees/pyRVEA.doctree and b/docs/_build/doctrees/modules.doctree differ diff --git a/docs/_build/doctrees/pyRVEA.EAs.doctree b/docs/_build/doctrees/pyRVEA.EAs.doctree deleted file mode 100644 index e4491d9..0000000 Binary files a/docs/_build/doctrees/pyRVEA.EAs.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyRVEA.OtherTools.doctree b/docs/_build/doctrees/pyRVEA.OtherTools.doctree deleted file mode 100644 index b531ce2..0000000 Binary files a/docs/_build/doctrees/pyRVEA.OtherTools.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyRVEA.Population.doctree b/docs/_build/doctrees/pyRVEA.Population.doctree deleted file mode 100644 index 0797057..0000000 Binary files a/docs/_build/doctrees/pyRVEA.Population.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyRVEA.Problem.doctree b/docs/_build/doctrees/pyRVEA.Problem.doctree deleted file mode 100644 index d726240..0000000 Binary files a/docs/_build/doctrees/pyRVEA.Problem.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyRVEA.Recombination.doctree b/docs/_build/doctrees/pyRVEA.Recombination.doctree deleted file mode 100644 index ebe7804..0000000 Binary files a/docs/_build/doctrees/pyRVEA.Recombination.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyRVEA.Selection.doctree b/docs/_build/doctrees/pyRVEA.Selection.doctree deleted file mode 100644 index b5dd232..0000000 Binary files a/docs/_build/doctrees/pyRVEA.Selection.doctree and /dev/null differ diff --git a/docs/_build/doctrees/pyrvea.EAs.doctree b/docs/_build/doctrees/pyrvea.EAs.doctree new file mode 100644 index 0000000..7e8a22c Binary files /dev/null and b/docs/_build/doctrees/pyrvea.EAs.doctree differ diff --git a/docs/_build/doctrees/pyrvea.OtherTools.doctree b/docs/_build/doctrees/pyrvea.OtherTools.doctree new file mode 100644 index 0000000..a145f1c Binary files /dev/null and b/docs/_build/doctrees/pyrvea.OtherTools.doctree differ diff --git a/docs/_build/doctrees/pyrvea.Population.doctree b/docs/_build/doctrees/pyrvea.Population.doctree new file mode 100644 index 0000000..2a0399d Binary files /dev/null and b/docs/_build/doctrees/pyrvea.Population.doctree differ diff --git a/docs/_build/doctrees/pyrvea.Problem.doctree b/docs/_build/doctrees/pyrvea.Problem.doctree new file mode 100644 index 0000000..a334d99 Binary files /dev/null and b/docs/_build/doctrees/pyrvea.Problem.doctree differ diff --git a/docs/_build/doctrees/pyrvea.Recombination.doctree b/docs/_build/doctrees/pyrvea.Recombination.doctree new file mode 100644 index 0000000..753a744 Binary files /dev/null and b/docs/_build/doctrees/pyrvea.Recombination.doctree differ diff --git a/docs/_build/doctrees/pyrvea.Selection.doctree b/docs/_build/doctrees/pyrvea.Selection.doctree new file mode 100644 index 0000000..d0666e4 Binary files /dev/null and b/docs/_build/doctrees/pyrvea.Selection.doctree differ diff --git a/docs/_build/doctrees/pyrvea.doctree b/docs/_build/doctrees/pyrvea.doctree new file mode 100644 index 0000000..a648dc4 Binary files /dev/null and b/docs/_build/doctrees/pyrvea.doctree differ diff --git a/docs/_build/html/.buildinfo b/docs/_build/html/.buildinfo index 657dc54..d89b63b 100644 --- a/docs/_build/html/.buildinfo +++ b/docs/_build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: d041dea352c4b59a784f5b68df7e5d13 +config: efb815af13ea31610fd3ab35acb78487 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_build/html/_sources/README.md.txt b/docs/_build/html/_sources/README.md.txt index f07083d..42d0fbf 100644 --- a/docs/_build/html/_sources/README.md.txt +++ b/docs/_build/html/_sources/README.md.txt @@ -1,21 +1,103 @@ -# README -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/EchoBetaGlass/pyrvea/master) +# Evolutionary algorithms in pyRVEA -The python version reference vector guided evolutionary algorithm. +- [EvoNN](#what-is-evonn) +- [EvoDN2](#what-is-evodn2) +- [BioGP](#what-is-biogp) +- [PPGA](#what-is-ppga) +- [Notes](#notes) +- [References](#references) -Currently supported: Multi-objective minimization with visualization and interaction support. Preference is accepted as a reference point. +## Introduction +The engineering and scientific data that one receives from experiments or simulations from any industry is often very noisy, one needs to have a model to process them effectively. It is, however, very difficult to build a model which captures only the correct trends in the data while devoid of any implicit noise. The models can easily be overfitted so that they capture every fluctuation in the data set, both significant and noisy, or underfitted where some major trends may remain undetected or unrepresented. -To test the code, open the [binder link](https://mybinder.org/v2/gh/EchoBetaGlass/pyrvea/master) and read example.ipynb. +Evolutionary neural networks and genetic programming have succesfully been utilized to come around this problem and create balanced models. Thus, the purpose of these models is not to achieve the tightest fit, or the lowest training error, but to construct models that capture the correct trends in the data, while avoiding the problems of overfitting and underfitting. -See the details of RVEA in the following paper +Neural networks and genetic programming have efficiently been utilized for these purposes. This project introduces Python implementations of three evolutionary algrorithms, [EvoNN](#what-is-evonn), [EvoDN2](#what-is-evodn2) and [BioGP](#what-is-biogp). The models can be trained and optimized using the genetic algorithms available in pyRVEA. A predator-prey genetic algorithm ([PPGA](#what-is-ppga)) was also implemented in Python for this project. The user can choose to train and optimize the models with the existing reference vector (RVEA) algorithms, or using the PPGA. -R. Cheng, Y. Jin, M. Olhofer and B. Sendhoff, -A Reference Vector Guided Evolutionary Algorithm for Many-objective -Optimization, IEEE Transactions on Evolutionary Computation, 2016 +These algorithms use a concept of an optimal tradeoff between two objectives, leading to a [Pareto frontier](https://en.wikipedia.org/wiki/Pareto_efficiency#Pareto_frontier). When there are conflicting requirements in a problem, it essentially leads to a situation where none of the objectives would be able to attain their individual best. The Pareto frontier consists of solutions where the optima are contained in a set of best possible tradeoffs between the objectives. -The source code of pyrvea is implemented by Bhupinder Saini +## What is EvoNN? +In **Evo**lutionary **N**eural **N**etwork [[1]](#1) [[2]](#2), the population consists of feed-forward neural networks. Each network consists of an input layer, a hidden layer and an output layer. The data is fed to the networks via input nodes, which pass the information to a hidden layer, where each active connection receives a nonzero weight. The number of connections increases the complexity of the model. The hidden layer also includes a bias term. Then through a transfer function the hidden layer passes the values onwards to the next level where the weights are optimized and passed to the final output of the network. + +![EvoNN](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/evonn.png "An example EvoNN model") + +*Figure 1. An example EvoNN model. [[7]](#7)* + +The evolution happens in the lower part of the network (i.e. between the input layer and the hidden layer), where the weights are optimized using a genetic algorithm (see available [algorithms](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html) in pyRVEA). The two objectives to optimize here are the model's accuracy and complexity. Thus, both the training error and the complexity need to be minimized. The weights are altered using crossover and mutation operations. The upper part of the network is then optimized using a Linear Least Square (LLSQ) approach, which ensures the mathematical convergence to the Pareto front. The evolutionary algorithm then chooses the fittest of the individuals (the ones with the best tradeoff between accuracy and complexity) to go on to the next generation. + +## What is EvoDN2? +**Evo**lutionary **D**eep Neural **N**etwork [[3]](#3) is an extension to EvoNN using deep neural networks and has the capacity for deep learning. The principle of EvoDN2 is the same as EvoNN, but the structure of the networks is different. In EvoDN2, each network consists of multiple subnets, which take in subsets of the input variables so that each variable is used at least once. The subnets have an input layer and multiple hidden layers, and they are optimized just as EvoNN using a genetic algorithm. Finally, the subnets converge on a linear layer, optimized by LLSQ and are mapped to an output. Each subnet has a randomized number of layers and nodes on each layers based on the bounds set by the user. The number of subnets can also be set. + +![EvoDN2](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/evodn.png "An example EvoDN2 model") + +*Figure 2. An example EvoDN2 model. [[3]](#3)* + +The advantage of EvoDN2 over EvoNN is that it fares much better with larger data sets, which can have thousands of data points. With smaller data sets EvoDN2 performs similarly to EvoNN, although EvoDN2 models tend to have a tighter fit. + +The complexity calculation of EvoDN2 is also different from EvoNN. With EvoDN2, the complexity is calculated as the product function of all weight matrices within a subnet, and these weights are the summed together to get the total complexity of the model. This way the connections with a larger magnitude of weight values contribute more to the final value, and inactive connections will be discounted. + +## What is BioGP? +BioGP [[4]](#4) is a **Bi**-**o**bjective **g**enetic **p**rogramming technique, which similarly to EvoNN and EvoDN2 minimizes the model's training error and complexity using genetic algorithms. Whereas many conventional GP algorithms tend to only focus on minimizing the error, one advantage of BioGP is that by calculating the best possibly tradeoff between the error and the complexity, overfitting and underfitting can be addressed. BioGP is designed so that for the first number of generations, it minimizes the training error, after which it switches to bi-objective mode minimizing both error and complexity. + +The benefit of genetic programming in general is the flexibility of allowing the user to select the mathematical operations (function set and terminal set) involved in building the model. BioGP is also designed to combat bloat, where the models may grow larger and larger in size without increasing the fitness. + +The BioGP models are represented with a tree encoding. GP achieves its learning by utilizing a function set containing user-defined mathematical operations like division or square root, and a terminal set containing the variables and the constants. The advantage of GP is that it does not require any pre-defined configuration of weights, biases and transfer functions and thus, it can evolve any mathematical function representing the system being modeled. + +The BioGP tree has a linear node at the top (code-wise, the linear node is at depth=0), from which a number of subtrees emerge. Each of these subtrees represent a nonlinear function, consisting of function nodes and terminal nodes. The linear node takes a weighted sum of the outputs of the subtrees, adds a bias value, and optimizes the weights using LLSQ to calculate the final output of the tree. To handle bloat, BioGP uses a parameter called error reduction ratio which provides a simple quantification of the contribution that a single subtree makes toward the performance of the model. If the contribution is less than the limit set by the user, that subtree is terminated and a new one is grown in its place. + +![BioGP](https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/biogp.png "An example BioGP model") + + +*Figure 3. An example BioGP tree. [[4]](#4)* + +The complexity of the model depends on the number of function nodes in the tree, and the tree's total depth. A scalar parameter is used in the complexity function allowing the user to control whether the depth or the number of function nodes should weigh more in the calculation. + +## What is PPGA? +**P**redatory-**P**rey **G**enetic **A**lgorithm [[5]](#5) [[6]](#6) + +A population of prey signify the various models or solutions to the problem at hand. Weaker prey, i.e. bad models or solutions, are killed by predators. The predators and prey are placed in a lattice, in which they are free to roam. + +In each generation, each predator gets a certain number of turns to move about and hunt in its neighbourhood, killing the weaker prey, according to a fitness criteria. After this, each prey gets a certain number of moves to pursue a random walk and to reproduce with other prey. Each reproduction step generates two new prey from two parents, by crossing over their attributes and adding random mutations. After each prey has completed its move, the whole process starts again. + +As the weaker individuals get eliminated in each generation, the population as a whole becomes more fit, i.e. the individuals get closer to the true pareto-optimal solutions. + +## Notes + +The algorithms presented here have been created earlier in MATLAB, and these Python implementations have been using that code as a basis. Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + +The source code of pyRVEA is implemented by Bhupinder Saini. + +## Contact If you have any questions about the code, please contact: -Bhupinder Saini: bhupinder.s.saini@jyu.fi\ -Project researcher at University of Jyväskylä. \ No newline at end of file +Bhupinder Saini: bhupinder.s.saini@jyu.fi + +Project researcher at University of Jyväskylä. + +Rissanen Niko: nijosari@student.jyu.fi + +Research assistant at University of Jyväskylä. + +## References + +#### 1 +Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham. + +#### 2 +Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397. + +#### 3 +Swagata R., Bhupinder S., Chakrabarti, N. and Chakraborti, N. (2019). A new Deep Neural Network algorithm employed in the study of mechanical properties of micro-alloyed steel. Department of Metallurgical and Materials Engineering, Indian Institute of Technology. + +#### 4 +Giri, B. K., Hakanen, J., Miettinen, K., & Chakraborti, N. (2013). Genetic programming through bi-objective genetic algorithms with a study of a simulated moving bed process involving multiple objectives. Applied Soft Computing, 13(5), 2613-2623. + +#### 5 +Laumanns, M., Rudolph, G., & Schwefel, H. P. (1998). A spatial predator-prey approach to multi-objective optimization: A preliminary study. In International Conference on Parallel Problem Solving from Nature (pp. 241-249). Springer, Berlin, Heidelberg. + +#### 6 +Li, X. (2003). A real-coded predator-prey genetic algorithm for multiobjective optimization. In International Conference on Evolutionary Multi-Criterion Optimization (pp. 207-221). Springer, Berlin, Heidelberg. + +#### 7 +Bhupinder S. Optimization of Vanadium Microalloyed Steel Composition Using Evolutionary Deep Learning Techniques. Master's thesis. Department of Metallurgical and Materials Engineering, Indian Institute of Technology. diff --git a/docs/_build/html/_sources/creating_models_example.md.txt b/docs/_build/html/_sources/creating_models_example.md.txt new file mode 100644 index 0000000..e09b464 --- /dev/null +++ b/docs/_build/html/_sources/creating_models_example.md.txt @@ -0,0 +1,111 @@ +## Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP + +This example will show how to use the code and structure in pyRVEA to create models using EvoNN, EvoDN2 and BioGP ([see descriptions of the algorithms here](https://github.com/delamorte/pyRVEA/blob/master/docs/README.md)). The code is currently capable of training and optimizing the models with all of the genetic algorithms implemented in [pyRVEA/EAs](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). + +The basic workflow is as follows: +1. Create or import training data +2. Create a problem class which handles the training of the models +3. After training, create a new population and evolve it using the models to optimize the problem + +For training data, example functions can be found in pyRVEA/Problem/testproblem.py and test_functions.py packages, or a custom data set can be imported. + +Using [Fonseca-Fleming](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) two objective function with 2 variables as an example: +```python +import numpy as np +import pandas as pd +from pyrvea.Problem.testproblem import TestProblem +from pyrvea.Problem.dataproblem import DataProblem + +test_prob = TestProblem(name="Fonseca-Fleming", num_of_variables=2) + +# Random data for training +# x = list of variable names, y = list of objectives +dataset, x, y = test_prob.create_training_data(samples=500) +``` +Or you can import a data set, here an example data set for [ZDT1](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) problem with 30 variables and 1000 samples is used. The DataProblem class requires the names of the variables and objectives as lists. If your data set does not contain them in the header, you will have to create them yourself. +``` +dataset = pd.read_excel("ZDT1_1000.xls", header=0) +x = dataset.columns[0:30].tolist() +# x = ['x1', 'x2', 'x3', ...] +y = dataset.columns[30:].tolist() +# y = ['f1', 'f2'] +``` +After you have the data, create the DataProblem class and pass the data, variables and objectives. +``` +problem = DataProblem(data=dataset, x=x, y=y) +``` +You can split the data into a training and testing set: +``` +problem.train_test_split(train_size=0.7) +``` +Parameters can be passed for the model and for the genetic algorithm as dictionaries. If no parameters are passed, the defaults are used. +Select the model and the genetic algorithm you want to use and set the parameters (or use defaults). Check [EA documentation](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html) for details for the genetic algorithms and see docs for [EvoNN parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.evonn_problem.EvoNNModel.set_params), [EvoDN2 parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.evodn2_problem.EvoDN2Model.set_params) and [BioGP parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.biogp_problem.BioGPModel.set_params). + +Both EA parameters and the model parameters can greatly affect the performance of the model. The best options depend on the problem, so experimenting with different values is encouraged. + +``` +from pyrvea.EAs.PPGA import PPGA + +ea_parameters = { + "generations_per_iteration": 10, + "iterations": 10, +} + +model_parameters = { + "training_algorithm": PPGA +} + +problem.train( + model_type="EvoDN2", + model_parameters=model_parameters, + ea_parameters=ea_parameters) +``` + +Note that for BioGP, function set and terminal should be adjusted according to the problem. By default, function set includes addition, substraction, multiplication and division, and terminal set includes the variables from the data. +For [Fonseca-Fleming function](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization), square root and negative should be added to the function set and constants 1 and 2 to the terminal set: +``` +f_set = ("add", "sub", "mul", "div", "sqrt", "neg") +t_set = [1, 2] + +model_parameters = { + function_set = f_set + terminal_set = t_set +} + +problem.train( + model_type="BioGP", + model_parameters=model_parameters +) +``` + +The models can currently be trained with available algorithms in [pyRVEA/EAs](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). For explanations of the different EAs, see their respective [documentation](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). + +The model's prediction vs. target values can be plotted as follows: +``` +# Prediction for f1 +f1_y_pred = problem.models["f1"][0].predict(problem.data[problem.x]) + +problem.models["f1"][0].plot( + f1_y_pred, np.asarray(problem.data["f1"]), name="filename" + "f1" +) +# Prediction for f2 +f2_y_pred = problem.models["f2"][0].predict(problem.data[problem.x]) + +problem.models["f2"][0].plot( + f2_y_pred, np.asarray(problem.data["f2"]), name="filename" + "f2" +) +``` + +After the models have been trained, the objectives can be optimized by creating a new population, passing the data problem class (containing the trained models) and calling evolve. EA parameters can be modified for optimization phase if wanted. + +``` +from pyrvea.EAs.RVEA import RVEA + +pop = Population(problem) +opt_params = {"iterations": 10, "generations_per_iteration": 25} +pop.evolve(EA=RVEA, ea_parameters=opt_params) +``` +To show the final pareto plot: +``` +pop.plot_pareto(name="my-test-function") +``` diff --git a/docs/_build/html/_sources/index.rst.txt b/docs/_build/html/_sources/index.rst.txt index 1dcdf36..2bb3223 100644 --- a/docs/_build/html/_sources/index.rst.txt +++ b/docs/_build/html/_sources/index.rst.txt @@ -18,7 +18,7 @@ Welcome to pyrvea's documentation! .. toctree:: :maxdepth: 4 :caption: Contents: - + README.md + creating_models_example.md pyrvea - diff --git a/docs/_build/html/_sources/modules.rst.txt b/docs/_build/html/_sources/modules.rst.txt new file mode 100644 index 0000000..81819d5 --- /dev/null +++ b/docs/_build/html/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +pyrvea +====== + +.. toctree:: + :maxdepth: 4 + + pyrvea diff --git a/docs/_build/html/_sources/pyRVEA.EAs.rst.txt b/docs/_build/html/_sources/pyRVEA.EAs.rst.txt deleted file mode 100644 index 7163385..0000000 --- a/docs/_build/html/_sources/pyRVEA.EAs.rst.txt +++ /dev/null @@ -1,26 +0,0 @@ -pyrvea.EAs -================== - -pyrvea.EAs.NSGAIII module -------------------------- - -.. automodule:: pyrvea.EAs.NSGAIII - :members: - :undoc-members: - :show-inheritance: - -pyrvea.EAs.RVEA module ----------------------- - -.. automodule:: pyrvea.EAs.RVEA - :members: - :undoc-members: - :show-inheritance: - -pyrvea.EAs.baseEA module ------------------------- - -.. automodule:: pyrvea.EAs.baseEA - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/pyRVEA.Population.rst.txt b/docs/_build/html/_sources/pyRVEA.Population.rst.txt deleted file mode 100644 index f9e2618..0000000 --- a/docs/_build/html/_sources/pyRVEA.Population.rst.txt +++ /dev/null @@ -1,11 +0,0 @@ -pyrvea.Population -========================= - - -pyrvea.Population.Population module ------------------------------------ - -.. automodule:: pyrvea.Population.Population - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/pyRVEA.Problem.rst.txt b/docs/_build/html/_sources/pyRVEA.Problem.rst.txt deleted file mode 100644 index 7624fff..0000000 --- a/docs/_build/html/_sources/pyRVEA.Problem.rst.txt +++ /dev/null @@ -1,21 +0,0 @@ -pyrvea.Problem package -====================== - -Submodules ----------- - -pyrvea.Problem.baseProblem module ---------------------------------- - -.. automodule:: pyrvea.Problem.baseProblem - :members: - :undoc-members: - :show-inheritance: - -pyrvea.Problem.testProblem module ---------------------------------- - -.. automodule:: pyrvea.Problem.testProblem - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/pyRVEA.Recombination.rst.txt b/docs/_build/html/_sources/pyRVEA.Recombination.rst.txt deleted file mode 100644 index 87cec6a..0000000 --- a/docs/_build/html/_sources/pyRVEA.Recombination.rst.txt +++ /dev/null @@ -1,10 +0,0 @@ -pyrvea.Recombination package -============================ - -Module contents ---------------- - -.. automodule:: pyrvea.Recombination - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/_build/html/_sources/pyRVEA.Selection.rst.txt b/docs/_build/html/_sources/pyRVEA.Selection.rst.txt deleted file mode 100644 index 5b5c45f..0000000 --- a/docs/_build/html/_sources/pyRVEA.Selection.rst.txt +++ /dev/null @@ -1,22 +0,0 @@ -pyrvea.Selection package -======================== - -Submodules ----------- - -pyrvea.Selection.APD\_select module ------------------------------------ - -.. automodule:: pyrvea.Selection.APD_select - :members: - :undoc-members: - :show-inheritance: - -pyrvea.Selection.NSGAIII\_select module ---------------------------------------- - -.. automodule:: pyrvea.Selection.NSGAIII_select - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/_build/html/_sources/pyRVEA.rst.txt b/docs/_build/html/_sources/pyRVEA.rst.txt deleted file mode 100644 index 8962c62..0000000 --- a/docs/_build/html/_sources/pyRVEA.rst.txt +++ /dev/null @@ -1,13 +0,0 @@ -pyrvea package -============== - - -.. toctree:: - - pyrvea.EAs - pyrvea.OtherTools - pyrvea.Population - pyrvea.Problem - pyrvea.Recombination - pyrvea.Selection - diff --git a/docs/_build/html/_sources/pyrvea.EAs.rst.txt b/docs/_build/html/_sources/pyrvea.EAs.rst.txt new file mode 100644 index 0000000..5c8d51b --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.EAs.rst.txt @@ -0,0 +1,62 @@ +pyrvea.EAs package +================== + +Submodules +---------- + +pyrvea.EAs.NSGAIII module +------------------------- + +.. automodule:: pyrvea.EAs.NSGAIII + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.PPGA module +---------------------- + +.. automodule:: pyrvea.EAs.PPGA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.RVEA module +---------------------- + +.. automodule:: pyrvea.EAs.RVEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.TournamentEA module +------------------------------ + +.. automodule:: pyrvea.EAs.TournamentEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.baseEA module +------------------------ + +.. automodule:: pyrvea.EAs.baseEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.slowRVEA module +-------------------------- + +.. automodule:: pyrvea.EAs.slowRVEA + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.EAs + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyRVEA.OtherTools.rst.txt b/docs/_build/html/_sources/pyrvea.OtherTools.rst.txt similarity index 59% rename from docs/_build/html/_sources/pyRVEA.OtherTools.rst.txt rename to docs/_build/html/_sources/pyrvea.OtherTools.rst.txt index c89ab07..136cd63 100644 --- a/docs/_build/html/_sources/pyRVEA.OtherTools.rst.txt +++ b/docs/_build/html/_sources/pyrvea.OtherTools.rst.txt @@ -1,44 +1,54 @@ -pyrvea.OtherTools +pyrvea.OtherTools package ========================= +Submodules +---------- pyrvea.OtherTools.IsNotebook module ----------------------------------- .. automodule:: pyrvea.OtherTools.IsNotebook - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.ReferenceVectors module ----------------------------------------- .. automodule:: pyrvea.OtherTools.ReferenceVectors - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.newRV module ------------------------------ .. automodule:: pyrvea.OtherTools.newRV - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.plotlyanimate module -------------------------------------- .. automodule:: pyrvea.OtherTools.plotlyanimate - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.symmetric\_vectors module ------------------------------------------- .. automodule:: pyrvea.OtherTools.symmetric_vectors - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: pyrvea.OtherTools + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyrvea.Population.rst.txt b/docs/_build/html/_sources/pyrvea.Population.rst.txt new file mode 100644 index 0000000..2fc8990 --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.Population.rst.txt @@ -0,0 +1,30 @@ +pyrvea.Population package +========================= + +Submodules +---------- + +pyrvea.Population.Population module +----------------------------------- + +.. automodule:: pyrvea.Population.Population + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Population.create\_individuals module +-------------------------------------------- + +.. automodule:: pyrvea.Population.create_individuals + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Population + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyrvea.Problem.rst.txt b/docs/_build/html/_sources/pyrvea.Problem.rst.txt new file mode 100644 index 0000000..fb6bbe6 --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.Problem.rst.txt @@ -0,0 +1,70 @@ +pyrvea.Problem package +====================== + +Submodules +---------- + +pyrvea.Problem.baseproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.baseproblem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.biogp\_problem module +------------------------------------ + +.. automodule:: pyrvea.Problem.biogp_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.dataproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.dataproblem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.evodn2\_problem module +------------------------------------- + +.. automodule:: pyrvea.Problem.evodn2_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.evonn\_problem module +------------------------------------ + +.. automodule:: pyrvea.Problem.evonn_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.test\_functions module +------------------------------------- + +.. automodule:: pyrvea.Problem.test_functions + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.testproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.testproblem + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Problem + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyrvea.Recombination.rst.txt b/docs/_build/html/_sources/pyrvea.Recombination.rst.txt new file mode 100644 index 0000000..3ab58c7 --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.Recombination.rst.txt @@ -0,0 +1,62 @@ +pyrvea.Recombination package +============================ + +Submodules +---------- + +pyrvea.Recombination.biogp\_mutation module +------------------------------------------- + +.. automodule:: pyrvea.Recombination.biogp_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.biogp\_xover module +---------------------------------------- + +.. automodule:: pyrvea.Recombination.biogp_xover + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.bounded\_polynomial\_mutation module +--------------------------------------------------------- + +.. automodule:: pyrvea.Recombination.bounded_polynomial_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.evodn2\_xover\_mutation module +--------------------------------------------------- + +.. automodule:: pyrvea.Recombination.evodn2_xover_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.evonn\_xover\_mutation module +-------------------------------------------------- + +.. automodule:: pyrvea.Recombination.evonn_xover_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.simulated\_binary\_crossover module +-------------------------------------------------------- + +.. automodule:: pyrvea.Recombination.simulated_binary_crossover + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Recombination + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyrvea.Selection.rst.txt b/docs/_build/html/_sources/pyrvea.Selection.rst.txt new file mode 100644 index 0000000..87ce021 --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.Selection.rst.txt @@ -0,0 +1,38 @@ +pyrvea.Selection package +======================== + +Submodules +---------- + +pyrvea.Selection.APD\_select module +----------------------------------- + +.. automodule:: pyrvea.Selection.APD_select + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Selection.NSGAIII\_select module +--------------------------------------- + +.. automodule:: pyrvea.Selection.NSGAIII_select + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Selection.tournament\_select module +------------------------------------------ + +.. automodule:: pyrvea.Selection.tournament_select + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Selection + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_sources/pyrvea.rst.txt b/docs/_build/html/_sources/pyrvea.rst.txt new file mode 100644 index 0000000..43d0b0a --- /dev/null +++ b/docs/_build/html/_sources/pyrvea.rst.txt @@ -0,0 +1,22 @@ +pyrvea package +============== + +Subpackages +----------- + +.. toctree:: + + pyrvea.EAs + pyrvea.OtherTools + pyrvea.Population + pyrvea.Problem + pyrvea.Recombination + pyrvea.Selection + +Module contents +--------------- + +.. automodule:: pyrvea + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_build/html/_static/basic.css b/docs/_build/html/_static/basic.css index 53acd09..c41d718 100644 --- a/docs/_build/html/_static/basic.css +++ b/docs/_build/html/_static/basic.css @@ -289,6 +289,12 @@ img.align-center, .figure.align-center, object.align-center { margin-right: auto; } +img.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + .align-left { text-align: left; } @@ -297,6 +303,10 @@ img.align-center, .figure.align-center, object.align-center { text-align: center; } +.align-default { + text-align: center; +} + .align-right { text-align: right; } @@ -368,6 +378,11 @@ table.align-center { margin-right: auto; } +table.align-default { + margin-left: auto; + margin-right: auto; +} + table caption span.caption-number { font-style: italic; } diff --git a/docs/_build/html/_static/documentation_options.js b/docs/_build/html/_static/documentation_options.js index d8cfb06..6d86510 100644 --- a/docs/_build/html/_static/documentation_options.js +++ b/docs/_build/html/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.1', + VERSION: '', LANGUAGE: 'None', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', diff --git a/docs/_build/html/_static/searchtools.js b/docs/_build/html/_static/searchtools.js index bdc2706..6031f99 100644 --- a/docs/_build/html/_static/searchtools.js +++ b/docs/_build/html/_static/searchtools.js @@ -319,12 +319,13 @@ var Search = { for (var prefix in objects) { for (var name in objects[prefix]) { var fullname = (prefix ? prefix + '.' : '') + name; - if (fullname.toLowerCase().indexOf(object) > -1) { + var fullnameLower = fullname.toLowerCase() + if (fullnameLower.indexOf(object) > -1) { var score = 0; - var parts = fullname.split('.'); + var parts = fullnameLower.split('.'); // check for different match types: exact matches of full name or // "last name" (i.e. last dotted part) - if (fullname == object || parts[parts.length - 1] == object) { + if (fullnameLower == object || parts[parts.length - 1] == object) { score += Scorer.objNameMatch; // matches in last name } else if (parts[parts.length - 1].indexOf(object) > -1) { diff --git a/docs/_build/html/creating_models_example.html b/docs/_build/html/creating_models_example.html new file mode 100644 index 0000000..ce4ebef --- /dev/null +++ b/docs/_build/html/creating_models_example.html @@ -0,0 +1,309 @@ + + + + + + + + + + + Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP
  • + + +
  • + + + View page source + + +
  • + +
+ + +
+
+
+
+ +
+

Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP

+

This example will show how to use the code and structure in pyRVEA to create models using EvoNN, EvoDN2 and BioGP (see descriptions of the algorithms here). The code is currently capable of training and optimizing the models with all of the genetic algorithms implemented in pyRVEA/EAs.

+

The basic workflow is as follows:

+
    +
  1. Create or import training data

  2. +
  3. Create a problem class which handles the training of the models

  4. +
  5. After training, create a new population and evolve it using the models to optimize the problem

  6. +
+

For training data, example functions can be found in pyRVEA/Problem/testproblem.py and test_functions.py packages, or a custom data set can be imported.

+

Using Fonseca-Fleming two objective function with 2 variables as an example:

+
import numpy as np
+import pandas as pd
+from pyrvea.Problem.testproblem import TestProblem
+from pyrvea.Problem.dataproblem import DataProblem
+
+test_prob = TestProblem(name="Fonseca-Fleming", num_of_variables=2)
+
+# Random data for training
+# x = list of variable names, y = list of objectives
+dataset, x, y = test_prob.create_training_data(samples=500)
+
+
+

Or you can import a data set, here an example data set for ZDT1 problem with 30 variables and 1000 samples is used. The DataProblem class requires the names of the variables and objectives as lists. If your data set does not contain them in the header, you will have to create them yourself.

+
dataset = pd.read_excel("ZDT1_1000.xls", header=0)
+x = dataset.columns[0:30].tolist()
+# x = ['x1', 'x2', 'x3', ...]
+y = dataset.columns[30:].tolist()
+# y = ['f1', 'f2']
+
+
+

After you have the data, create the DataProblem class and pass the data, variables and objectives.

+
problem = DataProblem(data=dataset, x=x, y=y)
+
+
+

You can split the data into a training and testing set:

+
problem.train_test_split(train_size=0.7)
+
+
+

Parameters can be passed for the model and for the genetic algorithm as dictionaries. If no parameters are passed, the defaults are used. +Select the model and the genetic algorithm you want to use and set the parameters (or use defaults). Check EA documentation for details for the genetic algorithms and see docs for EvoNN parameters, EvoDN2 parameters and BioGP parameters.

+

Both EA parameters and the model parameters can greatly affect the performance of the model. The best options depend on the problem, so experimenting with different values is encouraged.

+
from pyrvea.EAs.PPGA import PPGA
+
+ea_parameters = {
+    "generations_per_iteration": 10,
+    "iterations": 10,
+}
+
+model_parameters = {
+    "training_algorithm": PPGA
+}
+
+problem.train(
+    model_type="EvoDN2",
+    model_parameters=model_parameters,
+    ea_parameters=ea_parameters)
+
+
+

Note that for BioGP, function set and terminal should be adjusted according to the problem. By default, function set includes addition, substraction, multiplication and division, and terminal set includes the variables from the data. +For Fonseca-Fleming function, square root and negative should be added to the function set and constants 1 and 2 to the terminal set:

+
f_set = ("add", "sub", "mul", "div", "sqrt", "neg")
+t_set = [1, 2]
+
+model_parameters = {
+    function_set = f_set
+    terminal_set = t_set
+}
+
+problem.train(
+    model_type="BioGP",
+    model_parameters=model_parameters
+)
+
+
+

The models can currently be trained with available algorithms in pyRVEA/EAs. For explanations of the different EAs, see their respective documentation.

+

The model’s prediction vs. target values can be plotted as follows:

+
# Prediction for f1
+f1_y_pred = problem.models["f1"][0].predict(problem.data[problem.x])
+
+problem.models["f1"][0].plot(
+    f1_y_pred, np.asarray(problem.data["f1"]), name="filename" + "f1"
+)
+# Prediction for f2
+f2_y_pred = problem.models["f2"][0].predict(problem.data[problem.x])
+
+problem.models["f2"][0].plot(
+    f2_y_pred, np.asarray(problem.data["f2"]), name="filename" + "f2"
+)
+
+
+

After the models have been trained, the objectives can be optimized by creating a new population, passing the data problem class (containing the trained models) and calling evolve. EA parameters can be modified for optimization phase if wanted.

+
from pyrvea.EAs.RVEA import RVEA
+
+pop = Population(problem)
+opt_params = {"iterations": 10, "generations_per_iteration": 25}
+pop.evolve(EA=RVEA, ea_parameters=opt_params)
+
+
+

To show the final pareto plot:

+
pop.plot_pareto(name="my-test-function")
+
+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/genindex.html b/docs/_build/html/genindex.html new file mode 100644 index 0000000..a7bd10c --- /dev/null +++ b/docs/_build/html/genindex.html @@ -0,0 +1,923 @@ + + + + + + + + + + + + Index — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Index
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | G + | H + | I + | L + | M + | N + | O + | P + | R + | S + | T + | U + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ + + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/index.html b/docs/_build/html/index.html new file mode 100644 index 0000000..a7498ed --- /dev/null +++ b/docs/_build/html/index.html @@ -0,0 +1,299 @@ + + + + + + + + + + + Welcome to pyrvea’s documentation! — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

Welcome to pyrvea’s documentation!

+
+
+
+

Contents:

+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/modules.html b/docs/_build/html/modules.html new file mode 100644 index 0000000..eb1b5bf --- /dev/null +++ b/docs/_build/html/modules.html @@ -0,0 +1,267 @@ + + + + + + + + + + + pyrvea — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea

+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/objects.inv b/docs/_build/html/objects.inv index 8924e89..dc4b110 100644 Binary files a/docs/_build/html/objects.inv and b/docs/_build/html/objects.inv differ diff --git a/docs/_build/html/py-modindex.html b/docs/_build/html/py-modindex.html new file mode 100644 index 0000000..c4026c8 --- /dev/null +++ b/docs/_build/html/py-modindex.html @@ -0,0 +1,386 @@ + + + + + + + + + + + Python Module Index — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Python Module Index
  • + + +
  • + +
  • + +
+ + +
+
+
+
+ + +

Python Module Index

+ +
+ p +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ p
+ pyrvea +
    + pyrvea.EAs +
    + pyrvea.EAs.baseEA +
    + pyrvea.EAs.NSGAIII +
    + pyrvea.EAs.PPGA +
    + pyrvea.EAs.RVEA +
    + pyrvea.EAs.slowRVEA +
    + pyrvea.EAs.TournamentEA +
    + pyrvea.OtherTools +
    + pyrvea.OtherTools.IsNotebook +
    + pyrvea.OtherTools.newRV +
    + pyrvea.OtherTools.plotlyanimate +
    + pyrvea.OtherTools.ReferenceVectors +
    + pyrvea.OtherTools.symmetric_vectors +
    + pyrvea.Population +
    + pyrvea.Population.create_individuals +
    + pyrvea.Population.Population +
    + pyrvea.Problem +
    + pyrvea.Problem.baseproblem +
    + pyrvea.Problem.biogp_problem +
    + pyrvea.Problem.dataproblem +
    + pyrvea.Problem.evodn2_problem +
    + pyrvea.Problem.evonn_problem +
    + pyrvea.Problem.test_functions +
    + pyrvea.Problem.testproblem +
    + pyrvea.Recombination +
    + pyrvea.Recombination.biogp_mutation +
    + pyrvea.Recombination.biogp_xover +
    + pyrvea.Recombination.bounded_polynomial_mutation +
    + pyrvea.Recombination.evodn2_xover_mutation +
    + pyrvea.Recombination.evonn_xover_mutation +
    + pyrvea.Recombination.simulated_binary_crossover +
    + pyrvea.Selection +
    + pyrvea.Selection.APD_select +
    + pyrvea.Selection.NSGAIII_select +
    + pyrvea.Selection.tournament_select +
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.EAs.html b/docs/_build/html/pyrvea.EAs.html new file mode 100644 index 0000000..91268bf --- /dev/null +++ b/docs/_build/html/pyrvea.EAs.html @@ -0,0 +1,944 @@ + + + + + + + + + + + pyrvea.EAs package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.EAs package

+
+

Submodules

+
+
+

pyrvea.EAs.NSGAIII module

+
+
+class pyrvea.EAs.NSGAIII.NSGAIII(population: Population, ea_parameters)
+

Bases: pyrvea.EAs.baseEA.BaseDecompositionEA

+

Python Implementation of NSGA-III. Based on the pymoo package.

+

[description]

+

Methods

+ ++++ + + + + + + + + + + + + + + +

continue_evolution(self)

Checks whether the current iteration should be continued or not.

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population)

Describe a selection mechanism.

set_params(self, population, …[, logfile])

Set up the parameters.

+
+
+set_params(self, population:'Population', population_size:int=None, lattice_resolution:int=None, interact:bool=False, a_priori_preference:bool=False, generations_per_iteration:int=10, iterations:int=10, plotting:bool=True, logging:bool=False, logfile=None, **kwargs)
+

Set up the parameters. Save in self.params

+
+ +
+
+select(self, population:'Population')
+

Describe a selection mechanism. Return indices of selected +individuals.

+
+
Parameters
+

population (Population) – Contains the current population and problem +information.

+
+
Returns
+

List of indices of individuals to be selected.

+
+
Return type
+

list

+
+
+
+ +
+ +
+
+

pyrvea.EAs.PPGA module

+
+
+class pyrvea.EAs.PPGA.PPGA(population: pyrvea.Population.Population.Population, ea_parameters)
+

Bases: object

+

Predatory-Prey genetic algorithm.

+

A population of prey signify the various models or solutions to the problem at hand. +Weaker prey, i.e. bad models or solutions, are killed by predators. +The predators and prey are placed in a lattice, in which they are free to roam.

+

In each generation, each predator gets a certain number of turns to move about and hunt +in its neighbourhood, killing the weaker prey, according to a fitness criteria. After this, each +prey gets a certain number of moves to pursue a random walk and to reproduce with +other prey. Each reproduction step generates two new prey from two parents, by +crossing over their attributes and adding random mutations. After each prey has +completed its move, the whole process starts again.

+

As the weaker individuals get eliminated in each generation, the population as a whole becomes more fit, +i.e. the individuals get closer to the true pareto-optimal solutions.

+

If you have any questions about the code, please contact:

+

Bhupinder Saini: bhupinder.s.saini@jyu.fi +Project researcher at University of Jyväskylä.

+
+
Parameters
+
    +
  • population (object) – The population object

  • +
  • ea_parameters (dict) – PPGA specific parameters

  • +
+
+
+

Notes

+

The algorithm has been created earlier in MATLAB, and this Python implementation has been using +that code as a basis. +See references [4] for the study during which the original MATLAB version was created. +Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti.

+

For the MATLAB implementation, see: +N. Chakraborti. Data-Driven Bi-Objective Genetic Algorithms EvoNN and BioGP and Their Applications in Metallurgical +and Materials Domain. In Datta, Shubhabrata, Davim, J. Paulo (eds.), Computational Approaches to +Materials Design: Theoretical and Practical Aspects, pp. 346-369, 2016.

+

References

+

[1] Laumanns, M., Rudolph, G., & Schwefel, H. P. (1998). A spatial predator-prey approach to multi-objective +optimization: A preliminary study. +In International Conference on Parallel Problem Solving from Nature (pp. 241-249). Springer, Berlin, Heidelberg.

+

[2] Li, X. (2003). A real-coded predator-prey genetic algorithm for multiobjective optimization. In International +Conference on Evolutionary Multi-Criterion Optimization (pp. 207-221). Springer, Berlin, Heidelberg.

+

[3] Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. +In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham.

+

[4] Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net +applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397.

+

Methods

+ ++++ + + + + + + + + + + + + + + +

continue_evolution(self)

Checks whether the current iteration should be continued or not.

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population[, max_rank])

Of the population, individuals lower than max_rank are selected.

set_params(self, population, …)

Set up the parameters.

+
+
+set_params(self, population:'Population', target_pop_size:int=100, predator_pop_size:int=50, prey_max_moves:int=10, prob_prey_move:float=0.3, offspring_place_attempts:int=10, generations_per_iteration:int=10, iterations:int=10, kill_interval:int=7, max_rank:int=20, prob_crossover:float=0.8, prob_mutation:float=0.3, mut_strength:float=0.9, neighbourhood_radius:int=3, **kwargs)
+

Set up the parameters.

+
+
Parameters
+
    +
  • population (Population) – Population object.

  • +
  • target_pop_size (int) – Target population size.

  • +
  • predator_pop_size (int) – Predator population size.

  • +
  • prey_max_moves (int) – Number of turns the prey can try to move.

  • +
  • prob_prey_move (float) – Prey move in the lattice based on this probability.

  • +
  • offspring_place_attempts (int) – Number of tries to place to offspring to the lattice.

  • +
  • generations_per_iteration (int) – Number of generations per iteration.

  • +
  • iterations (int) – Total number of iterations.

  • +
  • kill_interval (int) – Kill all individuals worse than max_rank in the population every interval generation.

  • +
  • max_rank (int) – Individuals < max_rank will be preserved after kill_interval.

  • +
  • prob_crossover (float) – Probability of crossover occurring.

  • +
  • prob_mutation (float) – Probability of mutation occurring.

  • +
  • mut_strength (float) – Strength of the mutation.

  • +
  • neighbourhood_radius (int) – Radius of neighbourhood, or range of vision for predators.

  • +
+
+
Returns
+

Parameters for the algorithm.

+
+
Return type
+

dict

+
+
+
+ +
+
+select(self, population, max_rank=20) → list
+

Of the population, individuals lower than max_rank are selected. +Return indices of selected individuals.

+
+
Parameters
+
    +
  • population (Population) – Contains the current population and problem +information.

  • +
  • max_rank (int) – Select only individuals lower than max_rank

  • +
+
+
Returns
+

List of indices of individuals to be selected.

+
+
Return type
+

list

+
+
+
+ +
+
+continue_iteration(self)
+

Checks whether the current iteration should be continued or not.

+
+ +
+
+continue_evolution(self) → bool
+

Checks whether the current iteration should be continued or not.

+
+ +
+ +
+
+class pyrvea.EAs.PPGA.Lattice(size_x, size_y, params)
+

Bases: object

+

The 2-dimensional toroidal lattice in which the predators and prey are placed.

+
+
+size_x
+

Width of the lattice.

+
+
Type
+

int

+
+
+
+ +
+
+size_y
+

Height of the lattice.

+
+
Type
+

int

+
+
+
+ +
+
+lattice
+

2d array for the lattice.

+
+
Type
+

ndarray

+
+
+
+ +
+
+predator_pop
+

The predator population.

+
+
Type
+

ndarray

+
+
+
+ +
+
+predators_loc
+

Location (x, y) of predators on the lattice.

+
+
Type
+

list

+
+
+
+ +
+
+preys_loc
+

Location (x, y) of preys on the lattice.

+
+
Type
+

list

+
+
+
+ +
+
+params
+

Parameters for the algorithm

+
+
Type
+

dict

+
+
+
+ +

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + +

init_predators(self)

Initialize the predator population, linearly distributed in [0,1] and place them in the lattice randomly.

init_prey(self)

Find an empty position in the lattice and place the prey.

lattice_wrap_idx(index, lattice_shape)

Returns periodic lattice index for a given iterable index.

move_predator(self)

Find an empty position in the predator neighbourhood for the predators to move in, move the predator and kill the weakest prey in its neighbourhood, if any.

move_prey(self)

Find an empty position in prey neighbourhood for the prey to move in, and choose a mate for breeding if any available.

neighbours(arr, x, y[, n])

Given a 2D-array, returns an n*n array whose “center” element is arr[x,y]

place_offspring(self, offspring)

Try to place the offsprings to the lattice.

update_lattice(self[, selected])

Update prey positions in the lattice.

+
+
+init_predators(self)
+

Initialize the predator population, linearly distributed in [0,1] +and place them in the lattice randomly.

+
+ +
+
+init_prey(self)
+

Find an empty position in the lattice and place the prey.

+
+ +
+
+move_prey(self)
+

Find an empty position in prey neighbourhood for the prey to move in, +and choose a mate for breeding if any available.

+
+
Returns
+

mating_pop – List of parent indices to use for mating

+
+
Return type
+

list

+
+
+
+ +
+
+place_offspring(self, offspring)
+

Try to place the offsprings to the lattice. If no empty spot found within +number of max attempts, do not place.

+
+
Parameters
+

offspring (int) – number of offsprings

+
+
Returns
+

Successfully placed offspring indices.

+
+
Return type
+

list

+
+
+
+ +
+
+move_predator(self)
+

Find an empty position in the predator neighbourhood for the predators to move in, +move the predator and kill the weakest prey in its neighbourhood, if any. +Repeat until > predator_max_moves.

+
+ +
+
+update_lattice(self, selected=None)
+

Update prey positions in the lattice.

+
+
Parameters
+

selected (list) – Indices of preys to be removed from the lattice.

+
+
+
+ +
+
+static lattice_wrap_idx(index, lattice_shape)
+

Returns periodic lattice index +for a given iterable index.

+
+
Parameters
+
    +
  • index (tuple) – one integer for each axis

  • +
  • lattice_shape (tuple) – the shape of the lattice to index to

  • +
+
+
+
+ +
+
+static neighbours(arr, x, y, n=3)
+

Given a 2D-array, returns an n*n array whose “center” element is arr[x,y]

+
+
Parameters
+
    +
  • arr (ndarray) – A 2D-array where to get the neighbouring cells

  • +
  • x (int) – X coordinate for the center element

  • +
  • y (int) – Y coordinate for the center element

  • +
  • n (int) – Radius of the neighbourhood

  • +
+
+
Returns
+

+
+
Return type
+

The neighbouring cells of x, y in radius n*n. Defaults to Moore neighbourhood (n=3)

+
+
+
+ +
+ +
+
+

pyrvea.EAs.RVEA module

+
+
+class pyrvea.EAs.RVEA.RVEA(population: Population, ea_parameters)
+

Bases: pyrvea.EAs.baseEA.BaseDecompositionEA

+

The python version reference vector guided evolutionary algorithm.

+

See the details of RVEA in the following paper

+

R. Cheng, Y. Jin, M. Olhofer and B. Sendhoff, A Reference Vector Guided +Evolutionary Algorithm for Many-objective Optimization, IEEE Transactions on +Evolutionary Computation, 2016

+

The source code of pyrvea is implemented by Bhupinder Saini

+

If you have any questions about the code, please contact:

+

Bhupinder Saini: bhupinder.s.saini@jyu.fi

+

Project researcher at University of Jyväskylä.

+

Methods

+ ++++ + + + + + + + + + + + + + + +

continue_evolution(self)

Checks whether the current iteration should be continued or not.

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population)

Describe a selection mechanism.

set_params(self, population, …)

Set up the parameters.

+
+
+set_params(self, population:'Population', population_size:int=None, lattice_resolution:int=None, interact:bool=False, a_priori_preference:bool=False, generations_per_iteration:int=100, iterations:int=10, Alpha:float=2, **kwargs)
+

Set up the parameters. Save in RVEA.params. Note, this should be +changed to align with the current structure.

+
+
Parameters
+
    +
  • population (Population) – Population object

  • +
  • population_size (int) – Population Size

  • +
  • lattice_resolution (int) – Lattice resolution

  • +
  • interact (bool) – bool to enable or disable interaction. Enabled if True

  • +
  • a_priori_preference (bool) – similar to interact

  • +
  • generations_per_iteration (int) – Number of generations per iteration.

  • +
  • iterations (int) – Total Number of iterations.

  • +
  • Alpha (float) – The alpha parameter of APD selection.

  • +
+
+
+
+ +
+
+select(self, population:'Population')
+

Describe a selection mechanism. Return indices of selected +individuals.

+

# APD Based selection. # This is different from the paper. # +params.genetations != total number of generations. This is a compromise. +Also this APD uses an archived ideal point, rather than current, potentially +worse ideal point.

+
+
Parameters
+

population (Population) – Population information

+
+
Returns
+

list: Indices of selected individuals.

+
+
Return type
+

list

+
+
+
+ +
+ +
+
+

pyrvea.EAs.TournamentEA module

+
+
+class pyrvea.EAs.TournamentEA.TournamentEA(population: pyrvea.Population.Population.Population, ea_parameters)
+

Bases: object

+

Methods

+ ++++ + + + + + + + + + + + +

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population)

Select parents for recombination using tournament selection.

set_params(self, population, …)

Set up the parameters.

+
+
+set_params(self, population:'Population', tournament_size:int=5, target_pop_size:int=500, generations_per_iteration:int=10, iterations:int=10, prob_crossover:float=0.9, prob_mutation:float=0.3, min_fitness:float=0.001)
+

Set up the parameters.

+
+
Parameters
+
    +
  • population (Population) – Population object.

  • +
  • tournament_size (int) – Number of participants in tournament selection.

  • +
  • target_pop_size (int) – Desired population size.

  • +
  • generations_per_iteration (int) – Number of generations per iteration.

  • +
  • iterations (int) – Total number of iterations.

  • +
  • prob_crossover (float) – Probability of crossover occurring.

  • +
  • prob_mutation (float) – Probability of mutation occurring.

  • +
  • min_fitness (float) – If error of the best solution < min_fitness, stop evolution.

  • +
+
+
Returns
+

params – Parameters for the algorithm.

+
+
Return type
+

dict

+
+
+
+ +
+
+continue_iteration(self)
+

Checks whether the current iteration should be continued or not.

+
+ +
+
+select(self, population) → list
+

Select parents for recombination using tournament selection. +Chooses two parents, which are needed for crossover.

+
+
Parameters
+

population (Population) – Contains the current population and problem +information.

+
+
Returns
+

parents – List of indices of individuals to be selected.

+
+
Return type
+

list

+
+
+
+ +
+ +
+
+

pyrvea.EAs.baseEA module

+
+
+class pyrvea.EAs.baseEA.BaseEA
+

Bases: object

+

This class provides the basic structure for Evolutionary algorithms.

+

Methods

+ ++++ + + + + + +

set_params(self)

Set up the parameters.

+
+
+set_params(self)
+

Set up the parameters. Save in self.params

+
+ +
+ +
+
+class pyrvea.EAs.baseEA.BaseDecompositionEA(population: Population, ea_parameters)
+

Bases: pyrvea.EAs.baseEA.BaseEA

+

This class provides the basic structure for decomposition based +Evolutionary algorithms, such as RVEA or NSGA-III.

+

Methods

+ ++++ + + + + + + + + + + + + + + +

continue_evolution(self)

Checks whether the current iteration should be continued or not.

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population)

Describe a selection mechanism.

set_params(self)

Set up the parameters.

+
+
+select(self, population) → list
+

Describe a selection mechanism. Return indices of selected +individuals.

+
+
Parameters
+

population (Population) – Contains the current population and problem +information.

+
+
Returns
+

List of indices of individuals to be selected.

+
+
Return type
+

list

+
+
+
+ +
+
+continue_iteration(self)
+

Checks whether the current iteration should be continued or not.

+
+ +
+
+continue_evolution(self) → bool
+

Checks whether the current iteration should be continued or not.

+
+ +
+ +
+
+

pyrvea.EAs.slowRVEA module

+
+
+class pyrvea.EAs.slowRVEA.slowRVEA(population: Population, ea_parameters)
+

Bases: pyrvea.EAs.RVEA.RVEA

+

RVEA variant that impliments slow reference vector movement.

+

Methods

+ ++++ + + + + + + + + + + + + + + +

continue_evolution(self)

Checks whether the current iteration should be continued or not.

continue_iteration(self)

Checks whether the current iteration should be continued or not.

select(self, population)

Describe a selection mechanism.

set_params(self, population, …)

Set up the parameters.

+
+
+set_params(self, population:'Population', generations_per_iteration:int=10, iterations:int=10, Alpha:float=2, ref_point:list=None, old_point:list=None, **kwargs)
+

Set up the parameters. Save in RVEA.params. Note, this should be +changed to align with the current structure.

+
+
Parameters
+
    +
  • population (Population) – Population object

  • +
  • Alpha (float) – The alpha parameter of APD selection.

  • +
  • plotting (bool) – Useless really.

  • +
+
+
+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.OtherTools.html b/docs/_build/html/pyrvea.OtherTools.html new file mode 100644 index 0000000..875d321 --- /dev/null +++ b/docs/_build/html/pyrvea.OtherTools.html @@ -0,0 +1,807 @@ + + + + + + + + + + + pyrvea.OtherTools package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.OtherTools package

+
+

Submodules

+
+
+

pyrvea.OtherTools.IsNotebook module

+
+
+pyrvea.OtherTools.IsNotebook.IsNotebook() → bool
+

Checks if the current environment is a Jupyter Notebook or a console.

+
+
Returns
+

True if notebook. False if console

+
+
Return type
+

bool

+
+
+
+ +
+
+

pyrvea.OtherTools.ReferenceVectors module

+
+
+pyrvea.OtherTools.ReferenceVectors.normalize(vectors)
+

Normalize a set of vectors.

+

The length of the returned vectors will be unity.

+
+
Parameters
+

vectors (np.ndarray) – Set of vectors of any length, except zero.

+
+
+
+ +
+
+pyrvea.OtherTools.ReferenceVectors.shear(vectors, degrees:float=5)
+

Shear a set of vectors lying on the plane z=0 towards the z-axis, such that the +resulting vectors ‘degrees’ angle away from the z axis.

+

z is the last element of the vector, and has to be equal to zero.

+
+
Parameters
+
    +
  • vectors (numpy.ndarray) – The final element of each vector should be zero.

  • +
  • degrees (float, optional) – The angle that the resultant vectors make with the z axis. Unit is radians. +(the default is 5)

  • +
+
+
+
+ +
+
+pyrvea.OtherTools.ReferenceVectors.rotate(initial_vector, rotated_vector, other_vectors)
+

Calculate the rotation matrix that rotates the initial_vector to the +rotated_vector. Apply that rotation on other_vectors and return. +Uses Householder reflections twice to achieve this.

+
+ +
+
+pyrvea.OtherTools.ReferenceVectors.householder(vector)
+

Return reflection matrix via householder transformation.

+
+ +
+
+pyrvea.OtherTools.ReferenceVectors.rotate_toward(initial_vector, final_vector, other_vectors, degrees:float=5)
+

Rotate other_vectors (with the centre at initial_vector) towards final_vector +by an angle degrees.

+
+
Parameters
+
    +
  • initial_vector (np.ndarray) – Centre of the vectors to be rotated.

  • +
  • final_vector (np.ndarray) – The final position of the center of other_vectors.

  • +
  • other_vectors (np.ndarray) – The array of vectors to be rotated

  • +
  • degrees (float, optional) – The amount of rotation (the default is 5)

  • +
+
+
Returns
+

    +
  • rotated_vectors (np.ndarray) – The rotated vectors

  • +
  • reached (bool) – True if final_vector has been reached

  • +
+

+
+
+
+ +
+
+class pyrvea.OtherTools.ReferenceVectors.ReferenceVectors(lattice_resolution: int = None, number_of_objectives: int = None, creation_type: str = 'Uniform', vector_type: str = 'Spherical', ref_point: list = None)
+

Bases: object

+

Class object for reference vectors.

+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + +

adapt(self, fitness)

Adapt reference vectors.

add_edge_vectors(self)

Add edge vectors to the list of reference vectors.

iteractive_adapt_1(self, ref_point[, …])

Adapt reference vectors linearly towards a reference point.

neighbouring_angles(self)

Calculate neighbouring angles for normalization.

normalize(self)

Normalize the reference vectors to a unit hypersphere.

slow_interactive_adapt(self, ref_point)

Basically a wrapper around rotate_toward.

+
+
+normalize(self)
+

Normalize the reference vectors to a unit hypersphere.

+
+ +
+
+neighbouring_angles(self) → numpy.ndarray
+

Calculate neighbouring angles for normalization.

+
+ +
+
+adapt(self, fitness:numpy.ndarray)
+

Adapt reference vectors. Then normalize.

+
+
Parameters
+

fitness (np.ndarray) –

+
+
+
+ +
+
+iteractive_adapt_1(self, ref_point, translation_param=0.2)
+

Adapt reference vectors linearly towards a reference point. Then normalize.

+

The details can be found in the following paper: Hakanen, Jussi & +Chugh, Tinkle & Sindhya, Karthik & Jin, Yaochu & Miettinen, Kaisa. +(2016). Connections of Reference Vectors and Different Types of +Preference Information in Interactive Multiobjective Evolutionary +Algorithms.

+
+
Parameters
+
    +
  • ref_point

  • +
  • translation_param – (Default value = 0.2)

  • +
+
+
+
+ +
+
+slow_interactive_adapt(self, ref_point)
+

Basically a wrapper around rotate_toward. Slowly rotate ref vectors toward +ref_point. Return a boolean value to tell if the ref_point has been reached.

+
+
Parameters
+

ref_point (list or np.ndarray) – The reference vectors will slowly move towards the ref_point.

+
+
Returns
+

True if ref_point has been reached. False otherwise.

+
+
Return type
+

boolean

+
+
+
+ +
+
+add_edge_vectors(self)
+

Add edge vectors to the list of reference vectors.

+

Used to cover the entire orthant when preference information is +provided.

+
+ +
+ +
+
+

pyrvea.OtherTools.newRV module

+
+
+class pyrvea.OtherTools.newRV.newRV(lattice_resolution: int = None, number_of_objectives: int = None, creation_type: str = 'Uniform', vector_type: str = 'Spherical', ref_point: list = None)
+

Bases: pyrvea.OtherTools.ReferenceVectors.ReferenceVectors

+

pass

+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

adapt(self, fitness)

Adapt reference vectors.

add_edge_vectors(self)

Add edge vectors to the list of reference vectors.

interact_v2(self, ref_point)

New kind of interaction.

interact_v3(self, ref_point)

New kind of interaction.

iteractive_adapt_1(self, ref_point[, …])

Adapt reference vectors linearly towards a reference point.

neighbouring_angles(self)

Calculate neighbouring angles for normalization.

normalize(self)

Normalize the reference vectors to a unit hypersphere.

project_to_hyperplane(self)

Projects the reference vectors to the hyperplane xn = 1.

slow_interactive_adapt(self, ref_point)

Basically a wrapper around rotate_toward.

translate_to_hypersphere(self)

Reverse of preject_to_hyperplane().

+ ++++ + + + + + + + + +

revert_rotation

rotate_to_axis

+
+
+rotate_to_axis(self, ref_point)
+
+ +
+
+revert_rotation(self, ref_point)
+
+ +
+
+project_to_hyperplane(self)
+

Projects the reference vectors to the hyperplane xn = 1.

+
+ +
+
+translate_to_hypersphere(self)
+

Reverse of preject_to_hyperplane().

+
+ +
+
+interact_v2(self, ref_point)
+

New kind of interaction.

+
+ +
+
+interact_v3(self, ref_point)
+

New kind of interaction. More coverage.

+
+ +
+ +
+
+pyrvea.OtherTools.newRV.rotate(initial_vector, rotated_vector, other_vectors)
+

Calculate the rotation matrix that rotates the initial_vector to the +rotated_vector. Apply that rotation on other_vectors and return. +Uses Householder reflections twice to achieve this.

+
+ +
+
+pyrvea.OtherTools.newRV.normalize(vector)
+

Normalize and return a vector.

+
+ +
+
+pyrvea.OtherTools.newRV.householder(vector)
+

Return reflection matrix via householder transformation.

+
+ +
+
+pyrvea.OtherTools.newRV.dist_based_translation(vectors)
+

Translates points towards origin based on distance.

+
+ +
+
+pyrvea.OtherTools.newRV.main()
+
+ +
+
+

pyrvea.OtherTools.plotlyanimate module

+
+
+pyrvea.OtherTools.plotlyanimate.animate_init_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], filename:str) → dict
+

Plot the first (or zeroth) iteration of a population.

+

Intended as a frames object. Plots Scatter for 2D and 3D data. +Plots parallel coordinate plot for higher dimensional data.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – Contains the data to be plotted. Each row is an individual’s objective values.

  • +
  • filename (str) – Contains the name of the file to which the plot is saved.

  • +
+
+
Returns
+

Plotly figure object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_next_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], figure:dict, filename:str, generation:int=None) → dict
+

Plot the next set of individuals in an animation.

+

Plots scatter for 2D and 3D data, parallel coordinate plot for 4D and up.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – The objective values to be plotted

  • +
  • figure (dict) – Plotly figure object compatible dict

  • +
  • filename (str) – Name of the file to which the plot is saved

  • +
  • generation (int) – Iteration Number

  • +
+
+
Returns
+

Plotly Figure Object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_2d_init_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], filename:str) → dict
+

Initiate a 2D scatter animation.

+

Only for 2D data.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – Objective values

  • +
  • filename (str) – Name of the file to which plot is saved

  • +
+
+
Returns
+

Plotly Figure Object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_2d_next_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], figure:dict, filename:str, generation:int) → dict
+

Plot the next set of individuals in a 2D scatter animation.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – The objective values to be plotted

  • +
  • figure (dict) – Plotly figure object compatible dict

  • +
  • filename (str) – Name of the file to which the plot is saved

  • +
  • generation (int) – Iteration Number

  • +
+
+
Returns
+

Plotly Figure Object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_3d_init_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], filename:str) → dict
+

Plot the first (or zeroth) iteration of a population.

+

Intended as a frames object. Plots Scatter 3D data.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – Contains the data to be plotted. Each row is an individual’s objective values.

  • +
  • filename (str) – Contains the name of the file to which the plot is saved.

  • +
+
+
Returns
+

Plotly figure object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_3d_next_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], figure:dict, filename:str, generation:int) → dict
+

Plot the next set of individuals in an animation.

+

Plots scatter for 3D data.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – The objective values to be plotted

  • +
  • figure (dict) – Plotly figure object compatible dict

  • +
  • filename (str) – Name of the file to which the plot is saved

  • +
  • generation (int) – Iteration Number

  • +
+
+
Returns
+

Plotly Figure Object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_parallel_coords_init_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], filename:str) → dict
+

Plot the first (or zeroth) iteration of a population.

+

Intended as a frames object. Plots parallel coordinate plot for >3D data.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – Contains the data to be plotted. Each row is an individual’s objective values.

  • +
  • filename (str) – Contains the name of the file to which the plot is saved.

  • +
+
+
Returns
+

Plotly figure object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.animate_parallel_coords_next_(data:Union[numpy.ndarray, pandas.core.frame.DataFrame, list], figure:dict, filename:str, generation:int) → dict
+

Plot the next set of individuals in an animation.

+

Plots parallel coordinate plot for 4D and up.

+
+
Parameters
+
    +
  • data (Union[np.ndarray, pd.DataFrame, list]) – The objective values to be plotted

  • +
  • figure (dict) – Plotly figure object compatible dict

  • +
  • filename (str) – Name of the file to which the plot is saved

  • +
  • generation (int) – Iteration Number

  • +
+
+
Returns
+

Plotly Figure Object

+
+
Return type
+

dict

+
+
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.test()
+
+ +
+
+pyrvea.OtherTools.plotlyanimate.test2()
+
+ +
+
+

pyrvea.OtherTools.symmetric_vectors module

+
+
+pyrvea.OtherTools.symmetric_vectors.shear(vectors, degrees:float=5)
+

Shear a set of vectors lying on the plane z=0 towards the z-axis, such that the +resulting vectors ‘degrees’ angle away from the z axis.

+

z is the last element of the vector, and has to be equal to zero.

+
+
Parameters
+
    +
  • vectors (numpy.ndarray) – The final element of each vector should be zero.

  • +
  • degrees (float, optional) – The angle that the resultant vectors make with the z axis. Unit is radians. +(the default is 5)

  • +
+
+
+
+ +
+
+pyrvea.OtherTools.symmetric_vectors.normalize(vectors)
+

Normalize a set of vectors.

+

The length of the returned vectors will be unity.

+
+
Parameters
+

vectors (np.ndarray) – Set of vectors of any length, except zero.

+
+
+
+ +
+
+pyrvea.OtherTools.symmetric_vectors.rotate(initial_vector, rotated_vector, other_vectors)
+

Calculate the rotation matrix that rotates the initial_vector to the +rotated_vector. Apply that rotation on other_vectors and return. +Uses Householder reflections twice to achieve this.

+
+ +
+
+pyrvea.OtherTools.symmetric_vectors.householder(vector)
+

Return reflection matrix via householder transformation.

+
+ +
+
+pyrvea.OtherTools.symmetric_vectors.rotate_toward(initial_vector, final_vector, other_vectors, degrees:float=5)
+

Rotate other_vectors (with the centre at initial_vector) towards final_vector +by an angle degrees.

+
+
Parameters
+
    +
  • initial_vector (np.ndarray) – Centre of the vectors to be rotated.

  • +
  • final_vector (np.ndarray) – The final position of the center of other_vectors.

  • +
  • other_vectors (np.ndarray) – The array of vectors to be rotated

  • +
  • degrees (float, optional) – The amount of rotation (the default is 5)

  • +
+
+
Returns
+

    +
  • rotated_vectors (np.ndarray) – The rotated vectors

  • +
  • reached (bool) – True if final_vector has been reached

  • +
+

+
+
+
+ +
+
+pyrvea.OtherTools.symmetric_vectors.main()
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.Population.html b/docs/_build/html/pyrvea.Population.html new file mode 100644 index 0000000..3ef7281 --- /dev/null +++ b/docs/_build/html/pyrvea.Population.html @@ -0,0 +1,461 @@ + + + + + + + + + + + pyrvea.Population package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.Population package

+
+

Submodules

+
+
+

pyrvea.Population.Population module

+
+
+class pyrvea.Population.Population.Population(problem: BaseProblem, assign_type: str = 'RandomDesign', plotting: bool = False, pop_size=None, recombination_type=None, crossover_type='simulated_binary_crossover', mutation_type='bounded_polynomial_mutation', *args)
+

Bases: object

+

Define the population.

+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

add(self, new_pop)

Evaluate and add individuals to the population.

append_individual(self, ind)

Evaluate and add individual to the population.

delete(self, indices[, preserve])

Remove from population individuals which are in indices if preserve=False, otherwise preserve them and remove all others.

eval_fitness(self, obj)

Calculate fitness based on objective values.

evaluate_individual(self, ind)

Evaluate individual.

evolve(self, EA, ea_parameters)

Evolve the population with interruptions.

hypervolume(self, ref_point)

Calculate hypervolume.

mate(self[, mating_pop, params])

Conduct crossover and mutation over the population.

non_dominated(self)

Fix this.

plot_init_(self)

Initialize animation objects.

plot_objectives(self, iteration)

Plot the objective values of individuals in notebook.

plot_pareto(self, name[, show_all])

Plot the pareto front.

update_fitness(self)

Include or exclude objectives from fitness calculation.

update_ideal_and_nadir(self, new_objective_vals)

Updates self.ideal and self.nadir in the fitness space.

+
+
+add(self, new_pop:list)
+

Evaluate and add individuals to the population. Update ideal and nadir point.

+
+
Parameters
+

new_pop (list) – Decision variable values for new population.

+
+
+
+ +
+
+append_individual(self, ind:numpy.ndarray)
+

Evaluate and add individual to the population.

+
+
Parameters
+

ind (np.ndarray) –

+
+
+
+ +
+
+evaluate_individual(self, ind:numpy.ndarray)
+

Evaluate individual.

+

Returns objective values, constraint violation, and fitness.

+
+
Parameters
+

ind (np.ndarray) –

+
+
+
+ +
+
+eval_fitness(self, obj)
+

Calculate fitness based on objective values. Fitness = obj if minimized.

+
+ +
+
+update_fitness(self)
+

Include or exclude objectives from fitness calculation. +Problem.minimize should be a list of booleans of same length as the number of objectives.

+
+ +
+
+delete(self, indices, preserve=False)
+

Remove from population individuals which are in indices if preserve=False, otherwise +preserve them and remove all others.

+
+
Parameters
+
    +
  • indices (array_like) – Indices of individuals to keep or delete.

  • +
  • preserve (bool) – Whether to delete individuals at indices from current population, or preserve them and delete others.

  • +
+
+
+
+ +
+
+evolve(self, EA:'BaseEA'=None, ea_parameters:dict=None)
+

Evolve the population with interruptions.

+

Evolves the population based on the EA sent by the user.

+
+
Parameters
+
    +
  • EA ("BaseEA") – Should be a derivative of BaseEA (Default value = None)

  • +
  • ea_parameters (dict) – Contains the parameters needed by EA (Default value = None)

  • +
+
+
+
+ +
+
+mate(self, mating_pop=None, params=None)
+

Conduct crossover and mutation over the population.

+
+ +
+
+plot_init_(self)
+

Initialize animation objects. Return figure

+
+ +
+
+plot_objectives(self, iteration:int=None)
+

Plot the objective values of individuals in notebook. This is a hack.

+
+
Parameters
+

iteration (int) – Iteration count.

+
+
+
+ +
+
+plot_pareto(self, name, show_all=False)
+

Plot the pareto front.

+
+
Parameters
+
    +
  • name (str) – Name to append to the plot filename.

  • +
  • show_all (bool) – Show all solutions, including those not on the pareto front.

  • +
+
+
+
+ +
+
+hypervolume(self, ref_point)
+

Calculate hypervolume. Uses package pygmo. Add checks to prevent errors.

+
+
Parameters
+

ref_point

+
+
+
+ +
+
+non_dominated(self)
+

Fix this. check if nd2 and nds mean the same thing

+
+ +
+
+update_ideal_and_nadir(self, new_objective_vals:list=None)
+

Updates self.ideal and self.nadir in the fitness space.

+

Uses the entire population if new_objective_vals is none.

+
+
Parameters
+

new_objective_vals (list, optional) – Objective values for a newly added individual (the default is None, which +calculated the ideal and nadir for the entire population.)

+
+
+
+ +
+ +
+
+

pyrvea.Population.create_individuals module

+
+
+pyrvea.Population.create_individuals.create_new_individuals(design, problem, pop_size=None)
+

Create new individuals to the population.

+

The individuals can be created randomly, by LHS design, or can be passed by the +user.

+

Design does not apply in case of EvoNN and EvoDN2 problem, where neural networks are created +as individuals.

+
+
Parameters
+
    +
  • design (str, optional) – Describe the method of creation of new individuals. +“RandomDesign” creates individuals randomly. +“LHSDesign” creates individuals using Latin hypercube sampling. +“EvoNN” creates Artificial Neural Networks as individuals. +“EvoDN2” creates Deep Neural Networks.

  • +
  • problem (baseProblem) – An object of the class Problem

  • +
  • pop_size (int, optional) – Number of individuals in the population. If none, some default population +size based on number of objectives is chosen.

  • +
+
+
Returns
+

individuals – A list of individuals.

+
+
Return type
+

list

+
+
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.Problem.html b/docs/_build/html/pyrvea.Problem.html new file mode 100644 index 0000000..416e4c0 --- /dev/null +++ b/docs/_build/html/pyrvea.Problem.html @@ -0,0 +1,2087 @@ + + + + + + + + + + + pyrvea.Problem package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.Problem package

+
+

Submodules

+
+
+

pyrvea.Problem.baseproblem module

+
+
+class pyrvea.Problem.baseproblem.BaseProblem(name=None, num_of_variables=None, num_of_objectives=None, num_of_constraints=0, upper_limits=1, lower_limits=0)
+

Bases: object

+

Base class for the problems.

+

Methods

+ ++++ + + + + + + + + + + + +

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

objectives(self, decision_variables)

Accept a sample.

update(self)

Update the problem based on new information.

+
+
+objectives(self, decision_variables)
+

Accept a sample. Return Objective values.

+
+
Parameters
+

decision_variables

+
+
+
+ +
+
+constraints(self, decision_variables, objective_variables)
+

Accept a sample and/or corresponding objective values.

+
+
Parameters
+
    +
  • decision_variables

  • +
  • objective_variables

  • +
+
+
+
+ +
+
+update(self)
+

Update the problem based on new information.

+
+ +
+ +
+
+

pyrvea.Problem.biogp_problem module

+
+
+class pyrvea.Problem.biogp_problem.BioGP(name=None, X_train=None, y_train=None, num_of_objectives=2, params=None, num_samples=None, function_set=None, terminal_set=None)
+

Bases: pyrvea.Problem.baseproblem.BaseProblem

+

Creates syntax tree models to use for genetic programming through bi-objective genetic algorithms.

+

The BioGP technique initially minimizes training error through a single objective optimization procedure and then a +trade-off between complexity and accuracy is worked out through a genetic algorithm based bi-objective +optimization strategy.

+

The benefit of the BioGP approach is that an expert user or a decision maker (DM) can +flexibly select the mathematical operations involved to construct a meta-model of desired complexity or +accuracy. It is also designed to combat bloat – a perennial problem in genetic programming along with +over fitting and under fitting problems.

+

Notes

+

The algorithm has been created earlier in MATLAB, and this Python implementation has been using +that code as a basis.

+

Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti.

+
+
Parameters
+
    +
  • name (str) – Name of the problem.

  • +
  • X_train (np.ndarray) – Training data input.

  • +
  • y_train (np.ndarray) – Training data target values.

  • +
  • num_of_objectives (int) – The number of objectives.

  • +
  • params (dict) – Parameters for model training.

  • +
  • num_samples (int) – The number of data points, or samples.

  • +
  • function_set (array_like) – The function set to use when creating the trees.

  • +
  • terminal_set (array_like) – The terminals (variables and constants) to use when creating the trees.

  • +
+
+
+

References

+

[1] Giri, B. K., Hakanen, J., Miettinen, K., & Chakraborti, N. (2013). Genetic programming through bi-objective +genetic algorithms with a study of a simulated moving bed process involving multiple objectives. +Applied Soft Computing, 13(5), 2613-2623.

+

Methods

+ ++++ + + + + + + + + + + + + + + +

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

objectives(self, decision_variables)

Accept a sample.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

update(self)

Update the problem based on new information.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

add

cos

create_individuals

div

log

mul

neg

sin

sqrt

sub

tan

+
+
+create_individuals(self)
+
+ +
+
+objectives(self, decision_variables)
+

Accept a sample. Return Objective values.

+
+
Parameters
+

decision_variables

+
+
+
+ +
+
+select(self, pop, non_dom_front, selection='min_error')
+

Select target model from the population.

+
+
Parameters
+
    +
  • pop (obj) – The population object.

  • +
  • non_dom_front (list) – Indices of the models on the non-dominated front.

  • +
  • selection (str) – The criterion to use for selecting the model. +Possible values: ‘min_error’, ‘akaike_corrected’, ‘manual’

  • +
+
+
Returns
+

+
+
Return type
+

The selected model

+
+
+
+ +
+
+static add(x, y)
+
+ +
+
+static sub(x, y)
+
+ +
+
+static mul(x, y)
+
+ +
+
+static div(x, y)
+
+ +
+
+static sqrt(x)
+
+ +
+
+static log(x)
+
+ +
+
+static sin(x)
+
+ +
+
+static cos(x)
+
+ +
+
+static tan(x)
+
+ +
+
+static neg(x)
+
+ +
+ +
+
+class pyrvea.Problem.biogp_problem.BioGPModel(model_parameters=None, ea_parameters=None)
+

Bases: pyrvea.Problem.biogp_problem.BioGP

+

The class for the BioGP surrogate model.

+
+
Parameters
+
    +
  • model_parameters (dict) – Parameters passed for the model.

  • +
  • ea_parameters (dict) – Parameters passed for the genetic algorithm.

  • +
+
+
+
+
+name
+

Name of the model.

+
+
Type
+

str

+
+
+
+ +
+
+linear_node
+

The parent node of the tree containing the linear values.

+
+
Type
+

LinearNode

+
+
+
+ +
+
+fitness
+

Fitness of the trained model.

+
+
Type
+

list

+
+
+
+ +
+
+minimize
+

List of which objectives to minimize.

+
+
Type
+

list (bool)

+
+
+
+ +
+
+svr
+

Single variable response of the model.

+
+
Type
+

np.ndarray

+
+
+
+ +
+
+log
+

If logging set to True in params, external log file is stored here.

+
+
Type
+

file

+
+
+
+ +

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

create_logfile(self[, name])

Create a log file containing the parameters for training the model and the EA.

fit(self, training_data, target_values)

Fit data in BioGP model.

objectives(self, decision_variables)

Accept a sample.

plot(self, prediction, target[, name])

Creates and shows a plot for the model’s prediction.

predict(self, decision_variables)

Predict using the BioGP model.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

set_params(self[, name, training_algorithm, …])

Set parameters for the BioGP model.

single_variable_response(self[, ploton])

Get the model’s response to a single variable.

train(self)

Trains the networks and selects the best model from the non dominated front.

update(self)

Update the problem based on new information.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

add

cos

create_individuals

div

log

mul

neg

sin

sqrt

sub

tan

+
+
+set_params(self, name='BioGP_Model', training_algorithm=<class 'pyrvea.EAs.PPGA.PPGA'>, pop_size=500, max_depth=5, max_subtrees=4, prob_terminal=0.5, complexity_scalar=0.5, error_lim=0.001, init_method='ramped_half_and_half', selection='min_error', loss_func='root_mean_square', recombination_type=None, crossover_type='biogp_xover', mutation_type='biogp_mut', single_obj_generations=10, logging=False, plotting=False, function_set=('add', 'sub', 'mul', 'div'), terminal_set=None)
+

Set parameters for the BioGP model.

+
+
Parameters
+
    +
  • name (str) – Name of the problem.

  • +
  • training_algorithm (EA) – Which evolutionary algorithm to use for training the models.

  • +
  • pop_size (int) – Population size.

  • +
  • max_depth (int) – Maximum depth of the tree.

  • +
  • max_subtrees (int) – Maximum number of subtrees the tree can grow.

  • +
  • prob_terminal (float) – The probability of making the node terminal when growing the tree.

  • +
  • complexity_scalar (float) – Complexity of the model is calculated as a weighted aggregate of the maximum depth of the GP tree +and the total number of corresponding function nodes. Larger value gives more weight to the depth, +lower more weight to the number of function nodes.

  • +
  • error_lim (float) – Used to control bloat. If the error reduction ratio of a subtree is less than this value, +then that root is terminated and a new root is grown under the linear node (i.e., parent node).

  • +
  • init_method (str) –

    Method to use for creating the initial population. Can be either ‘grow’, ‘full’, or +‘ramped_half_and_half’ (default).

    +

    grow: nodes are chosen at random from both functions and terminals, allowing for smaller trees +than max_depth. +full: nodes are chosen from the function set until the max depth is reached, and then terminals are chosen. +ramped half and half: trees are grown with a 50/50 mixture of ‘grow’ and ‘full’.

    +

  • +
  • loss_func (str) – The loss function to use.

  • +
  • selection (str) – The selection method to use.

  • +
  • crossover_type, mutation_type (recombination_type,) – Recombination functions. If recombination_type is specified, crossover and mutation +will be handled by the same function. If None, they are done separately.

  • +
  • single_obj_generations (int) – How many generations to run minimizing only the training error.

  • +
  • logging (bool) – True to create a logfile, False otherwise.

  • +
  • plotting (bool) – True to create a plot, False otherwise.

  • +
  • function_set (tuple) – The function set to use when creating the trees.

  • +
  • terminal_set (list) – The terminals (variables and constants) to use when creating the trees.

  • +
+
+
+
+ +
+
+fit(self, training_data, target_values)
+

Fit data in BioGP model.

+
+
Parameters
+
    +
  • training_data (pd.DataFrame, shape = (numbers of samples, number of variables)) – Training data.

  • +
  • target_values (pd.DataFrame) – Target values.

  • +
+
+
Returns
+

self

+
+
Return type
+

returns an instance of self.

+
+
+
+ +
+
+train(self)
+

Trains the networks and selects the best model from the non dominated front.

+
+ +
+
+predict(self, decision_variables)
+

Predict using the BioGP model.

+
+
Parameters
+

decision_variables (pd.DataFrame) – The decision variables used for prediction.

+
+
Returns
+

y – The prediction of the model.

+
+
Return type
+

np.ndarray

+
+
+
+ +
+
+plot(self, prediction, target, name=None)
+

Creates and shows a plot for the model’s prediction.

+
+
Parameters
+
    +
  • prediction (np.ndarray) – The prediction of the model.

  • +
  • target (pd.DataFrame) – The target values.

  • +
  • name (str) – Filename to save the plot as.

  • +
+
+
+
+ +
+
+create_logfile(self, name=None)
+

Create a log file containing the parameters for training the model and the EA.

+
+
Parameters
+

name (str) – Filename to save the log as.

+
+
Returns
+

log_file – An external log file.

+
+
Return type
+

file

+
+
+
+ +
+
+single_variable_response(self, ploton=False)
+

Get the model’s response to a single variable.

+
+
Parameters
+

ploton (bool) – Create and show plot on/off.

+
+
+
+ +
+ +
+
+class pyrvea.Problem.biogp_problem.Node(value=None, depth=None, params=None, function_set=None, terminal_set=None)
+

Bases: object

+

A node object representing a function or terminal node in the tree.

+
+
Parameters
+
    +
  • value (function, str or float) – A function node has as its value a function. Terminal nodes contain variables which are either float or str.

  • +
  • depth (int) – The depth the node is at.

  • +
  • params (None or dict) – The parameters of the model.

  • +
  • function_set (array_like) – The function set to use when creating the trees.

  • +
  • terminal_set (array_like) – The terminals (variables and constants) to use when creating the trees.

  • +
+
+
+

Methods

+ ++++ + + + + + + + + +

get_sub_nodes(self)

Get all nodes belonging to the subtree under the current node.

grow_tree(self[, max_depth, method, depth, ind])

Create a random tree recursively using either grow or full method.

+ ++++ + + + + + + + + + + + + + + +

draw

draw_tree

node_label

predict

+
+
+predict(self, decision_variables=None)
+
+ +
+
+node_label(self)
+
+ +
+
+draw(self, dot, count)
+
+ +
+
+draw_tree(self, name='tree', footer='')
+
+ +
+
+get_sub_nodes(self)
+

Get all nodes belonging to the subtree under the current node.

+
+
Returns
+

nodes – A list of nodes in the subtree.

+
+
Return type
+

list

+
+
+
+ +
+
+grow_tree(self, max_depth=None, method='grow', depth=0, ind=None)
+

Create a random tree recursively using either grow or full method.

+
+
Parameters
+
    +
  • max_depth (int) – The maximum depth of the tree.

  • +
  • method (str) – Methods: ‘grow’, ‘full’. +For the ‘grow’ method, nodes are chosen at random from both functions and terminals. +The ‘full’ method chooses nodes from the function set until the max depth is reached, +and then terminals are chosen.

  • +
  • depth (int) – Current depth.

  • +
  • ind – The starting node from which to begin growing trees.

  • +
+
+
+
+ +
+ +
+
+class pyrvea.Problem.biogp_problem.LinearNode(value='linear', depth=0, params=None)
+

Bases: pyrvea.Problem.biogp_problem.Node

+

The parent node of the tree, from which a number of subtrees emerge, as defined +by the user. The linear node takes a weighted sum of the output from the subtrees and +also uses a bias value. The weights and the bias are calculated by the linear least +square technique.

+
+
Parameters
+
    +
  • value (function, str or float) – A function node has as its value a function. Terminal nodes contain variables which are either float or str.

  • +
  • depth (int) – The depth the node is at.

  • +
  • params (None or dict) – Parameters of the model.

  • +
+
+
+

Methods

+ ++++ + + + + + + + + +

get_sub_nodes(self)

Get all nodes belonging to the subtree under the current node.

grow_tree(self[, max_depth, method, depth, ind])

Create a random tree recursively using either grow or full method.

+ ++++ + + + + + + + + + + + + + + + + + +

calculate_linear

draw

draw_tree

node_label

predict

+
+
+calculate_linear(self, X_train, y_train)
+
+ +
+ +
+
+pyrvea.Problem.biogp_problem.random()
+
+ +
+
+

pyrvea.Problem.dataproblem module

+
+
+class pyrvea.Problem.dataproblem.DataProblem(data: pandas.core.frame.DataFrame = None, x: List[str] = None, y: List[str] = None, minimize: List[bool] = None, ideal: List[float] = None, nadir: List[float] = None, num_of_constraints=0, lower_limits: List[float] = None, upper_limits: List[float] = None, name='data_problem')
+

Bases: pyrvea.Problem.baseproblem.BaseProblem

+

Methods

+ ++++ + + + + + + + + + + + +

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

objectives(self, decision_variables)

Objectives function to use in optimization.

update(self)

Update the problem based on new information.

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

data_scaling

data_uniform_mapping

outlier_removal

retrain_surrogate

surrogates_predict

testing_score

train

train_test_split

transform_new_data

+
+
+data_scaling(self, data_decision)
+
+ +
+
+data_uniform_mapping(self)
+
+ +
+
+outlier_removal(self)
+
+ +
+
+train_test_split(self, train_size:float=0.8)
+
+ +
+
+train(self, model_type:str=None, objectives:str=None, **kwargs)
+
+ +
+
+transform_new_data(self, decision_variables)
+
+ +
+
+surrogates_predict(self, decision_variables)
+
+ +
+
+testing_score(self)
+
+ +
+
+retrain_surrogate(self)
+
+ +
+
+objectives(self, decision_variables)
+

Objectives function to use in optimization.

+
+
Parameters
+

decision_variables (ndarray) – The decision variables

+
+
Returns
+

objectives – The objective values

+
+
Return type
+

ndarray

+
+
+
+ +
+ +
+
+

pyrvea.Problem.evodn2_problem module

+
+
+class pyrvea.Problem.evodn2_problem.EvoDN2(name=None, X_train=None, y_train=None, num_of_objectives=2, num_samples=None, subsets=None, params=None)
+

Bases: pyrvea.Problem.baseproblem.BaseProblem

+

Creates Deep Neural Networks (DNN) for the EvoDN2 algorithm.

+

DNNs have a fixed number of subnets, each of which has a random number of +layers, and a random number of nodes in each layer, dependant on max layers +and max nodes set by user.

+

Notes

+

The algorithm has been created earlier in MATLAB, and this Python implementation has been using +that code as a basis.

+

Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti.

+
+
Parameters
+
    +
  • name (str) – Name of the problem

  • +
  • X_train (ndarray) – Training data input

  • +
  • y_train (ndarray) – Training data target values

  • +
  • num_of_objectives (int) – The number of objectives

  • +
  • num_samples (int) – The number of data points, or samples.

  • +
  • subsets (array_like) – A list of variables used for each subnet of the model.

  • +
  • params (dict) – Parameters for the models

  • +
+
+
+

References

+

[1] Swagata R., Bhupinder S., Chakrabarti, N. and Chakraborti, N. (2019). A new Deep Neural Network algorithm +employed in the study of mechanical properties of micro-alloyed steel. +Department of Metallurgical and Materials Engineering, Indian Institute of Technology.

+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + +

activation(self, decision_variables)

Calculates the dot product and applies the activation function.

calculate_linear(self, activated_layer)

Apply the linear function to the final output layer and calculate the training error.

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

objectives(self, decision_variables)

Use this method to calculate objective functions.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

update(self)

Update the problem based on new information.

+ ++++ + + + + + +

activate

+
+
+objectives(self, decision_variables) → list
+

Use this method to calculate objective functions.

+
+
Parameters
+

decision_variables (ndarray) – Variables from the neural network

+
+
Returns
+

obj_func – The objective function

+
+
Return type
+

list

+
+
+
+ +
+
+activation(self, decision_variables)
+

Calculates the dot product and applies the activation function. +:param decision_variables: Array of all subnets in the current neural network +:type decision_variables: ndarray

+
+
Returns
+

    +
  • non_linear_layer (ndarray) – The final non-linear layer before the output

  • +
  • complexity (float) – The complexity of the neural network

  • +
+

+
+
+
+ +
+
+calculate_linear(self, activated_layer)
+

Apply the linear function to the final output layer +and calculate the training error.

+
+
Parameters
+

activated_layer (ndarray) – Output of the activation function.

+
+
Returns
+

    +
  • linear_layer (ndarray) – The optimized output layer of the network.

  • +
  • predicted_values (ndarray) – The prediction of the model.

  • +
  • training_error (float) – Training error of the model.

  • +
+

+
+
+
+ +
+
+select(self, pop, non_dom_front, selection='min_error')
+

Select target model from the population.

+
+
Parameters
+
    +
  • pop (obj) – The population object.

  • +
  • non_dom_front (list) – Indices of the models on the non-dominated front.

  • +
  • selection (str) – The criterion to use for selecting the model. +Possible values: ‘min_error’, ‘manual’

  • +
+
+
Returns
+

    +
  • model – The selected model.

  • +
  • fitness – The model’s fitness values.

  • +
+

+
+
+
+ +
+
+static activate(name, x)
+
+ +
+ +
+
+class pyrvea.Problem.evodn2_problem.EvoDN2Model(model_parameters=None, ea_parameters=None)
+

Bases: pyrvea.Problem.evodn2_problem.EvoDN2

+

Class for the EvoDN2 surrogate model.

+
+
Parameters
+
    +
  • model_parameters (dict) – Parameters passed for the model.

  • +
  • ea_parameters (dict) – Parameters passed for the genetic algorithm.

  • +
+
+
+
+
+name
+

Name of the problem

+
+
Type
+

str

+
+
+
+ +
+
+subnets
+

A list containing the subnets of the model.

+
+
Type
+

array_like

+
+
+
+ +
+
+subsets
+

A list of variables used for each subnet of the model.

+
+
Type
+

array_like

+
+
+
+ +
+
+fitness
+

Fitness of the trained model.

+
+
Type
+

list

+
+
+
+ +
+
+non_linear_layer
+

The activated layer combining all of the model’s subnets.

+
+
Type
+

np.ndarray or None

+
+
+
+ +
+
+linear_layer
+

The final optimized layer of the network.

+
+
Type
+

np.ndarray or None

+
+
+
+ +
+
+svr
+

Single variable response of the model.

+
+
Type
+

array_like

+
+
+
+ +
+
+log
+

If logging set to True in params, external log file is stored here.

+
+
Type
+

file

+
+
+
+ +

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

activation(self, decision_variables)

Calculates the dot product and applies the activation function.

calculate_linear(self, activated_layer)

Apply the linear function to the final output layer and calculate the training error.

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

create_logfile(self[, name])

Create a log file containing the parameters for training the model and the EA.

fit(self, training_data, target_values)

Fit data in EvoDN2 model, divide input variables for each subnet randomly, and train the model.

objectives(self, decision_variables)

Use this method to calculate objective functions.

plot(self, prediction, target[, name])

Creates and shows a plot for the model’s prediction.

predict(self, decision_variables)

Predict using the EvoDN2 model.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

set_params(self[, name, training_algorithm, …])

Set parameters for EvoDN2 model.

single_variable_response(self[, ploton])

Get the model’s response to a single variable.

train(self)

Create a random population, evolve it and select a model based on selection.

update(self)

Update the problem based on new information.

+ ++++ + + + + + +

activate

+
+
+set_params(self, name='EvoDN2_Model', training_algorithm=<class 'pyrvea.EAs.PPGA.PPGA'>, pop_size=500, num_subnets=4, max_layers=4, max_nodes=4, prob_omit=0.2, w_low=-5.0, w_high=5.0, activation_func='sigmoid', opt_func='llsq', loss_func='root_mean_square', selection='min_error', recombination_type='evodn2_xover_mutation', crossover_type='standard', mutation_type='gaussian', logging=False, plotting=False)
+

Set parameters for EvoDN2 model.

+
+
Parameters
+
    +
  • name (str) – Name of the problem.

  • +
  • training_algorithm (EA) – Which training algorithm to use.

  • +
  • pop_size (int) – Population size.

  • +
  • num_subnets (int) – Number of subnets.

  • +
  • max_layers (int) – Maximum number of hidden layers in each subnet.

  • +
  • max_nodes (int) – Maximum number of nodes in each hidden layer.

  • +
  • prob_omit (float) – Probability of setting some weights to zero initially.

  • +
  • w_low (float) – The lower bound for randomly generated weights.

  • +
  • w_high (float) – The upper bound for randomly generated weights.

  • +
  • activation_func (str) – Function to use for activation.

  • +
  • opt_func (str) – Function to use for optimizing the final layer of the model.

  • +
  • loss_func (str) – The loss function to use.

  • +
  • selection (str) – The selection to use for selecting the model.

  • +
  • crossover_type, mutation_type (recombination_type,) – Recombination functions. If recombination_type is specified, crossover and mutation +will be handled by the same function. If None, they are done separately.

  • +
  • logging (bool) – True to create a logfile, False otherwise.

  • +
  • plotting (bool) – True to create a plot, False otherwise.

  • +
+
+
+
+ +
+
+fit(self, training_data, target_values)
+

Fit data in EvoDN2 model, divide input variables for each subnet randomly, +and train the model.

+
+
Parameters
+
    +
  • training_data (pd.DataFrame, shape = (numbers of samples, number of variables)) – Training data.

  • +
  • target_values (pd.DataFrame) – Target values.

  • +
+
+
Returns
+

self

+
+
Return type
+

returns an instance of self.

+
+
+
+ +
+
+train(self)
+

Create a random population, evolve it and select a model based on selection.

+
+ +
+
+predict(self, decision_variables)
+

Predict using the EvoDN2 model.

+
+
Parameters
+

decision_variables (pd.DataFrame) – The decision variables used for prediction.

+
+
Returns
+

y – The prediction of the model.

+
+
Return type
+

ndarray

+
+
+
+ +
+
+plot(self, prediction, target, name=None)
+

Creates and shows a plot for the model’s prediction.

+
+
Parameters
+
    +
  • prediction (np.ndarray) – The prediction of the model.

  • +
  • target (pd.DataFrame) – The target values.

  • +
  • name (str) – Filename to save the plot as.

  • +
+
+
+
+ +
+
+create_logfile(self, name=None)
+

Create a log file containing the parameters for training the model and the EA.

+
+
Returns
+

log_file – An external log file.

+
+
Return type
+

file

+
+
+
+ +
+
+single_variable_response(self, ploton=False)
+

Get the model’s response to a single variable.

+
+
Parameters
+

ploton (bool) – Create and show plot on/off.

+
+
+
+ +
+ +
+
+

pyrvea.Problem.evonn_problem module

+
+
+class pyrvea.Problem.evonn_problem.EvoNN(name=None, X_train=None, y_train=None, num_of_objectives=2, params=None, num_samples=None)
+

Bases: pyrvea.Problem.baseproblem.BaseProblem

+

Creates Artificial Neural Network (ANN) models for the EvoNN algorithm.

+

These models contain only one hidden node layer. The lower part of the network +is optimized by a genetic algorithm, and the upper part is optimized by Linear Least Square +algorithm by default.

+
+
Parameters
+
    +
  • name (str) – Name of the problem.

  • +
  • X_train (np.ndarray) – Training data input.

  • +
  • y_train (np.ndarray) – Training data target values.

  • +
  • num_of_objectives (int) – The number of objectives.

  • +
  • params (dict) – Parameters for model training.

  • +
  • num_samples (int) – The number of data points, or samples.

  • +
+
+
+

Notes

+

The algorithm has been created earlier in MATLAB, and this Python implementation has been using +that code as a basis.

+

Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti.

+

References

+

[1] Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. +In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham. +[2] Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net +applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397.

+

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + +

activation(self, non_linear_layer)

Calculates the dot product and applies the activation function.

calculate_linear(self, non_linear_layer)

Apply the linear function to the activated layer and calculate the training error.

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

information_criterion(self, decision_variables)

Calculate the information criterion.

objectives(self, decision_variables)

Use this method to calculate objective functions.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

update(self)

Update the problem based on new information.

+ ++++ + + + + + +

activate

+
+
+objectives(self, decision_variables) → list
+

Use this method to calculate objective functions.

+
+
Parameters
+

decision_variables (np.ndarray) – Variables from the neural network.

+
+
Returns
+

obj_func – The objective function.

+
+
Return type
+

list

+
+
+
+ +
+
+activation(self, non_linear_layer)
+

Calculates the dot product and applies the activation function. +Also get complexity for the lower part of the network.

+
+
Parameters
+

non_linear_layer (np.ndarray) – Weight matrix of the neural network.

+
+
Returns
+

    +
  • activated_layer (np.ndarray) – The activated non-linear layer before the output.

  • +
  • complexity (int) – The model’s complexity.

  • +
+

+
+
+
+ +
+
+calculate_linear(self, non_linear_layer)
+

Apply the linear function to the activated layer +and calculate the training error.

+
+
Parameters
+

non_linear_layer (np.ndarray) – Output of the activation function

+
+
Returns
+

    +
  • linear_layer (np.ndarray) – The optimized weight matrix of the upper part of the network

  • +
  • predicted_values (np.ndarray) – The prediction of the model

  • +
  • training_error (float) – The model’s training error

  • +
+

+
+
+
+ +
+
+information_criterion(self, decision_variables)
+

Calculate the information criterion.

+

Currently supports Akaike and corrected Akaike Information Criterion.

+
+
Returns
+

+
+
Return type
+

Corrected Akaike Information criterion

+
+
+
+ +
+
+select(self, pop, non_dom_front, selection='min_error')
+

Select target model from the population.

+
+
Parameters
+
    +
  • pop (obj) – The population object.

  • +
  • non_dom_front (list) – Indices of the models on the non-dominated front.

  • +
  • selection (str) – The criterion to use for selecting the model. +Possible values: ‘min_error’, ‘akaike_corrected’, ‘manual’

  • +
+
+
Returns
+

+
+
Return type
+

The selected model

+
+
+
+ +
+
+static activate(name, x)
+
+ +
+ +
+
+class pyrvea.Problem.evonn_problem.EvoNNModel(model_parameters=None, ea_parameters=None)
+

Bases: pyrvea.Problem.evonn_problem.EvoNN

+

The class for the EvoNN surrogate model.

+
+
Parameters
+
    +
  • model_parameters (dict) – Parameters passed for the model.

  • +
  • ea_parameters (dict) – Parameters passed for the genetic algorithm.

  • +
+
+
+
+
+name
+

Name of the model.

+
+
Type
+

str

+
+
+
+ +
+
+non_linear_layer
+

The weight matrix of the lower part of the network.

+
+
Type
+

np.ndarray

+
+
+
+ +
+
+linear_layer
+

The linear layer of the upper part of the network.

+
+
Type
+

np.ndarray

+
+
+
+ +
+
+fitness
+

Fitness of the trained model.

+
+
Type
+

list

+
+
+
+ +
+
+svr
+

Single variable response of the model.

+
+
Type
+

np.ndarray

+
+
+
+ +
+
+log
+

If logging set to True in params, external log file is stored here.

+
+
Type
+

file

+
+
+
+ +

Methods

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

activation(self, non_linear_layer)

Calculates the dot product and applies the activation function.

calculate_linear(self, non_linear_layer)

Apply the linear function to the activated layer and calculate the training error.

constraints(self, decision_variables, …)

Accept a sample and/or corresponding objective values.

create_logfile(self[, name])

Create a log file containing the parameters for training the model and the EA.

fit(self, training_data, target_values)

Fit data in EvoNN model.

information_criterion(self, decision_variables)

Calculate the information criterion.

objectives(self, decision_variables)

Use this method to calculate objective functions.

plot(self, prediction, target[, name])

Creates and shows a plot for the model’s prediction.

predict(self, decision_variables)

Predict using the EvoNN model.

select(self, pop, non_dom_front[, selection])

Select target model from the population.

set_params(self[, name, training_algorithm, …])

Set parameters for the EvoNN model.

single_variable_response(self[, ploton])

Get the model’s response to a single variable.

train(self)

Trains the networks and selects the best model from the non dominated front.

update(self)

Update the problem based on new information.

+ ++++ + + + + + +

activate

+
+
+set_params(self, name='EvoNN_Model', training_algorithm=<class 'pyrvea.EAs.PPGA.PPGA'>, pop_size=500, num_nodes=20, prob_omit=0.2, w_low=-5.0, w_high=5.0, activation_func='sigmoid', opt_func='llsq', loss_func='root_median_square', selection='akaike_corrected', recombination_type='evonn_xover_mutation', crossover_type='standard', mutation_type='gaussian', logging=False, plotting=False)
+

Set parameters for the EvoNN model.

+
+
Parameters
+
    +
  • name (str) – Name of the problem.

  • +
  • training_algorithm (EA) – Which evolutionary algorithm to use for training the models.

  • +
  • pop_size (int) – Population size.

  • +
  • num_nodes (int) – Maximum number of nodes per layer.

  • +
  • prob_omit (float) – Probability of setting some weights to zero initially.

  • +
  • w_low (float) – The lower bound for randomly generated weights.

  • +
  • w_high (float) – The upper bound for randomly generated weights.

  • +
  • activation_func (str) – Function to use for activation.

  • +
  • opt_func (str) – Function to use for optimizing the final layer of the model.

  • +
  • loss_func (str) – The loss function to use.

  • +
  • selection (str) – The selection to use for selecting the model.

  • +
  • crossover_type, mutation_type (recombination_type,) – Recombination functions. If recombination_type is specified, crossover and mutation +will be handled by the same function. If None, they are done separately.

  • +
  • logging (bool) – True to create a logfile, False otherwise.

  • +
  • plotting (bool) – True to create a plot, False otherwise.

  • +
+
+
+
+ +
+
+fit(self, training_data, target_values)
+

Fit data in EvoNN model.

+
+
Parameters
+
    +
  • training_data (pd.DataFrame, shape = (numbers of samples, number of variables)) – Training data.

  • +
  • target_values (pd.DataFrame) – Target values.

  • +
+
+
Returns
+

self

+
+
Return type
+

returns an instance of self.

+
+
+
+ +
+
+train(self)
+

Trains the networks and selects the best model from the non dominated front.

+
+ +
+
+predict(self, decision_variables)
+

Predict using the EvoNN model.

+
+
Parameters
+

decision_variables (pd.DataFrame) – The decision variables used for prediction.

+
+
Returns
+

y – The prediction of the model.

+
+
Return type
+

np.ndarray

+
+
+
+ +
+
+plot(self, prediction, target, name=None)
+

Creates and shows a plot for the model’s prediction.

+
+
Parameters
+
    +
  • prediction (np.ndarray) – The prediction of the model.

  • +
  • target (pd.DataFrame) – The target values.

  • +
  • name (str) – Filename to save the plot as.

  • +
+
+
+
+ +
+
+create_logfile(self, name=None)
+

Create a log file containing the parameters for training the model and the EA.

+
+
Parameters
+

name (str) – Filename to save the log as.

+
+
Returns
+

log_file – An external log file.

+
+
Return type
+

file

+
+
+
+ +
+
+single_variable_response(self, ploton=False)
+

Get the model’s response to a single variable.

+
+
Parameters
+

ploton (bool) – Create and show plot on/off.

+
+
+
+ +
+ +
+
+

pyrvea.Problem.test_functions module

+
+
+class pyrvea.Problem.test_functions.OptTestFunctions(name=None, num_of_variables=None)
+

Bases: object

+

Test functions for single/multi-objective problems to test +the performance of evolutionary algorithms.

+

See: https://en.wikipedia.org/wiki/Test_functions_for_optimization

+
+
Parameters
+
    +
  • name (str) – name of the test function

  • +
  • num_of_variables (int) – number of decision variables

  • +
  • num_of_objectives (int) – number of objectives

  • +
  • num_of_constraints (int) – number of constraints

  • +
  • upper_limits (float) – upper boundaries for test data

  • +
  • lower_limits (float) – lower boundaries for test data

  • +
+
+
+

Methods

+ ++++ + + + + + + + + + + + +

__call__(self, x)

Call self as a function.

create_training_data(self[, samples, …])

Create training data for test functions.

objectives(self, decision_variables)

Use this method to calculate objective functions.

+
+
+objectives(self, decision_variables) → list
+

Use this method to calculate objective functions.

+
+
Parameters
+

decision_variables (np.ndarray) – The decision variables.

+
+
Returns
+

+
+
Return type
+

The objective functions.

+
+
+
+ +
+
+create_training_data(self, samples=150, method='random', seed=None)
+

Create training data for test functions.

+
+
Parameters
+
    +
  • samples (int) – number of samples

  • +
  • method (str) – method to use in data creation. Possible values random, lhs, linear, linear+zeros, linear+reverse.

  • +
  • seed (int) – if a number is given, random data will be seeded

  • +
+
+
+
+ +
+ +
+
+

pyrvea.Problem.testproblem module

+
+
+class pyrvea.Problem.testproblem.TestProblem(name=None, num_of_variables=None, num_of_objectives=None, num_of_constraints=0, upper_limits=1.0, lower_limits=0.0)
+

Bases: pyrvea.Problem.baseproblem.BaseProblem

+

Test functions for single/multi-objective problems to test +the performance of evolutionary algorithms.

+

See: https://en.wikipedia.org/wiki/Test_functions_for_optimization

+
+
Parameters
+
    +
  • name (str) – Name of the test function.

  • +
  • num_of_variables (int) – Number of decision variables.

  • +
  • num_of_objectives (int) – Number of objectives.

  • +
  • num_of_constraints (int) – Number of constraints.

  • +
  • upper_limits (float) – Upper boundaries for test data.

  • +
  • lower_limits (float) – Lower boundaries for test data.

  • +
+
+
+

Methods

+ ++++ + + + + + + + + + + + + + + +

constraints(self, decision_variables, …)

Calculate constraint violation.

create_training_data(self[, samples, …])

Create training data for test functions.

objectives(self, decision_variables)

Use this method to calculate objective functions.

update(self)

Update the problem based on new information.

+
+
+objectives(self, decision_variables) → list
+

Use this method to calculate objective functions.

+
+
Parameters
+

decision_variables

+
+
+
+ +
+
+constraints(self, decision_variables, objective_variables)
+

Calculate constraint violation.

+
+
Parameters
+
    +
  • decision_variables

  • +
  • objective_variables

  • +
+
+
+
+ +
+
+create_training_data(self, samples=500, method='random', seed=None)
+

Create training data for test functions.

+
+
Parameters
+
    +
  • samples (int) – Number of samples.

  • +
  • method (str) – Method to use in data creation. Possible values random, lhs (latin hypercube sampling), linear.

  • +
  • seed (int) – If a number is given, random data will be seeded.

  • +
+
+
Returns
+

    +
  • dataset (Training data in a Pandas DataFrame, including all variables and objectives.)

  • +
  • x (List of variables)

  • +
  • y (List of objectives)

  • +
+

+
+
+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.Recombination.html b/docs/_build/html/pyrvea.Recombination.html new file mode 100644 index 0000000..dbace39 --- /dev/null +++ b/docs/_build/html/pyrvea.Recombination.html @@ -0,0 +1,384 @@ + + + + + + + + + + + pyrvea.Recombination package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.Recombination package

+
+

Submodules

+
+
+

pyrvea.Recombination.biogp_mutation module

+
+
+pyrvea.Recombination.biogp_mutation.mutate(offspring, individuals, params, *args)
+

Perform BioGP mutation functions.

+

Standard mutation: +Randomly select and regrow a subtree of an individual.

+

Small mutation: +Randomly select a node within a tree and replace it with either a function of the same arity, +or another value from the terminal set.

+

Mono parental: +Randomly swap two subtrees within the same individual.

+
+
Parameters
+
    +
  • offspring (list) – List of individuals to mutate.

  • +
  • individuals (list) – List of all individuals.

  • +
  • params (dict) – Parameters for breeding. If None, use defaults.

  • +
+
+
+
+ +
+
+

pyrvea.Recombination.biogp_xover module

+
+
+pyrvea.Recombination.biogp_xover.mate(mating_pop, individuals:list, params)
+

Perform BioGP crossover functions. Produce two offsprings by swapping genetic +material of the two parents.

+

Standard crossover: +Swap two random subtrees between the parents.

+

Height-fair crossover: +Swap two random subtrees between the parents at the selected depth.

+
+
Parameters
+
    +
  • mating_pop (list) – List of indices of individuals to mate. If None, choose from population randomly. +Each entry should contain two indices, one for each parent.

  • +
  • individuals (list) – List of all individuals.

  • +
  • params (dict) – Parameters for evolution. If None, use defaults.

  • +
+
+
Returns
+

offspring – The offsprings produced as a result of crossover.

+
+
Return type
+

list

+
+
+
+ +
+
+

pyrvea.Recombination.bounded_polynomial_mutation module

+
+
+pyrvea.Recombination.bounded_polynomial_mutation.mutate(offspring, individuals, params, lower_limits, upper_limits)
+

Bounded polynomial mutation.

+
+
Parameters
+
    +
  • offspring (List) – List of offspring to mutate.

  • +
  • individuals (List) – List of all individuals.

  • +
  • params (dict) – Parameters used for breeding.

  • +
  • lower_limits (float) – Problem lower bounds.

  • +
  • upper_limits (float) – Problem upper bounds.

  • +
+
+
+
+ +
+
+

pyrvea.Recombination.evodn2_xover_mutation module

+
+
+pyrvea.Recombination.evodn2_xover_mutation.mate(mating_pop, individuals:list, params, crossover_type=None, mutation_type=None)
+

Swap nodes between two partners and mutate based on standard deviation.

+
+
Parameters
+
    +
  • mating_pop (list) – List of indices of individuals to mate. If None, choose from population randomly. +Each entry should contain two indices, one for each parent.

  • +
  • individuals (list) – List of all individuals.

  • +
  • params (dict) – Parameters for evolution. If None, use defaults.

  • +
+
+
Returns
+

offspring – The offsprings produced as a result of crossover and mutation.

+
+
Return type
+

list

+
+
+
+ +
+
+

pyrvea.Recombination.evonn_xover_mutation module

+
+
+pyrvea.Recombination.evonn_xover_mutation.mate(mating_pop, individuals:list, params, crossover_type=None, mutation_type=None)
+

Swap nodes between two partners and mutate based on standard deviation.

+
+
Parameters
+
    +
  • mating_pop (list) – List of indices of individuals to mate. If None, choose from population randomly. +Each entry should contain two indices, one for each parent.

  • +
  • individuals (list) – List of all individuals.

  • +
  • params (dict) – Parameters for evolution. If None, use defaults.

  • +
+
+
Returns
+

offspring – The offsprings produced as a result of crossover and mutation.

+
+
Return type
+

list

+
+
+
+ +
+
+

pyrvea.Recombination.simulated_binary_crossover module

+
+
+pyrvea.Recombination.simulated_binary_crossover.mate(mating_pop, pop, params)
+

Simulated binary crossover.

+
+
Parameters
+
    +
  • mating_pop (list) – List of population to mate.

  • +
  • pop (list) – List of all individuals

  • +
  • params (dict) – Parameters for breeding. If None, use defaults.

  • +
+
+
Returns
+

offspring – The offspring produced as a result of crossover.

+
+
Return type
+

List

+
+
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.Selection.html b/docs/_build/html/pyrvea.Selection.html new file mode 100644 index 0000000..e8d5791 --- /dev/null +++ b/docs/_build/html/pyrvea.Selection.html @@ -0,0 +1,322 @@ + + + + + + + + + + + pyrvea.Selection package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea.Selection package

+
+

Submodules

+
+
+

pyrvea.Selection.APD_select module

+
+
+pyrvea.Selection.APD_select.APD_select(fitness:list, vectors:'ReferenceVectors', penalty_factor:float, ideal:list=None)
+

Select individuals for mating on basis of Angle penalized distance.

+
+
Parameters
+
    +
  • fitness (list) – Fitness of the current population.

  • +
  • vectors (ReferenceVectors) – Class containing reference vectors.

  • +
  • penalty_factor (float) – Multiplier of angular deviation from Reference +vectors. See RVEA paper for details.

  • +
  • ideal (list) – ideal point for the population. +Uses the min fitness value if None.

  • +
+
+
Returns
+

A list of indices of the selected individuals.

+
+
Return type
+

[type]

+
+
+
+ +
+
+

pyrvea.Selection.NSGAIII_select module

+
+
+pyrvea.Selection.NSGAIII_select.NSGAIII_select(fitness:list, ref_dirs:'ReferenceVectors', ideal_point:list=None, worst_point:list=None, extreme_points:list=None, n_survive:int=None)
+
+ +
+
+pyrvea.Selection.NSGAIII_select.get_extreme_points_c(F, ideal_point, extreme_points=None)
+

Taken from pymoo

+
+ +
+
+pyrvea.Selection.NSGAIII_select.get_nadir_point(extreme_points, ideal_point, worst_point, worst_of_front, worst_of_population)
+
+ +
+
+pyrvea.Selection.NSGAIII_select.niching(F, n_remaining, niche_count, niche_of_individuals, dist_to_niche)
+
+ +
+
+pyrvea.Selection.NSGAIII_select.associate_to_niches(F, ref_dirs, ideal_point, nadir_point, utopian_epsilon=0.0)
+
+ +
+
+pyrvea.Selection.NSGAIII_select.calc_niche_count(n_niches, niche_of_individuals)
+
+ +
+
+pyrvea.Selection.NSGAIII_select.calc_perpendicular_distance(N, ref_dirs)
+
+ +
+
+

pyrvea.Selection.tournament_select module

+
+
+pyrvea.Selection.tournament_select.tour_select(fitness, tournament_size)
+

Tournament selection. Choose number of individuals to participate +and select the one with the best fitness.

+
+
Parameters
+
    +
  • fitness (array_like) – An array of each individual’s fitness.

  • +
  • tournament_size (int) – Number of participants in the tournament.

  • +
+
+
Returns
+

The index of the best individual.

+
+
Return type
+

int

+
+
+
+ +
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/pyrvea.html b/docs/_build/html/pyrvea.html new file mode 100644 index 0000000..524bddd --- /dev/null +++ b/docs/_build/html/pyrvea.html @@ -0,0 +1,321 @@ + + + + + + + + + + + pyrvea package — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ +
+

pyrvea package

+
+

Subpackages

+
+ +
+
+
+

Module contents

+
+
+ + +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/search.html b/docs/_build/html/search.html new file mode 100644 index 0000000..ddfe6d5 --- /dev/null +++ b/docs/_build/html/search.html @@ -0,0 +1,212 @@ + + + + + + + + + + + Search — pyrvea documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+ +
    + +
  • Docs »
  • + +
  • Search
  • + + +
  • + + + +
  • + +
+ + +
+
+
+
+ + + + +
+ +
+ +
+ +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js index 74364c7..f753698 100644 --- a/docs/_build/html/searchindex.js +++ b/docs/_build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["README","index","pyrvea","pyrvea.EAs","pyrvea.OtherTools","pyrvea.Population","pyrvea.Problem","pyrvea.Recombination","pyrvea.Selection"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["README.md","index.rst","pyrvea.rst","pyrvea.EAs.rst","pyrvea.OtherTools.rst","pyrvea.Population.rst","pyrvea.Problem.rst","pyrvea.Recombination.rst","pyrvea.Selection.rst"],objects:{"pyrvea.EAs":{NSGAIII:[3,0,0,"-"],RVEA:[3,0,0,"-"],baseEA:[3,0,0,"-"]},"pyrvea.EAs.NSGAIII":{NSGAIII:[3,1,1,""]},"pyrvea.EAs.NSGAIII.NSGAIII":{select:[3,2,1,""],set_params:[3,2,1,""]},"pyrvea.EAs.RVEA":{RVEA:[3,1,1,""]},"pyrvea.EAs.RVEA.RVEA":{select:[3,2,1,""],set_params:[3,2,1,""]},"pyrvea.EAs.baseEA":{BaseDecompositionEA:[3,1,1,""],BaseEA:[3,1,1,""]},"pyrvea.EAs.baseEA.BaseDecompositionEA":{continue_evolution:[3,2,1,""],continue_iteration:[3,2,1,""],select:[3,2,1,""]},"pyrvea.EAs.baseEA.BaseEA":{set_params:[3,2,1,""]},"pyrvea.OtherTools":{IsNotebook:[4,0,0,"-"],ReferenceVectors:[4,0,0,"-"],plotlyanimate:[4,0,0,"-"]},"pyrvea.OtherTools.IsNotebook":{IsNotebook:[4,3,1,""]},"pyrvea.OtherTools.ReferenceVectors":{ReferenceVectors:[4,1,1,""]},"pyrvea.OtherTools.ReferenceVectors.ReferenceVectors":{adapt:[4,2,1,""],add_edge_vectors:[4,2,1,""],iteractive_adapt_1:[4,2,1,""],neighbouring_angles:[4,2,1,""],normalize:[4,2,1,""]},"pyrvea.OtherTools.plotlyanimate":{animate_2d_init_:[4,3,1,""],animate_2d_next_:[4,3,1,""],animate_3d_init_:[4,3,1,""],animate_3d_next_:[4,3,1,""],animate_init_:[4,3,1,""],animate_next_:[4,3,1,""],animate_parallel_coords_init_:[4,3,1,""],animate_parallel_coords_next_:[4,3,1,""],test2:[4,3,1,""],test:[4,3,1,""]},"pyrvea.Population":{Population:[5,0,0,"-"]},"pyrvea.Population.Population":{Population:[5,1,1,""]},"pyrvea.Population.Population.Population":{add:[5,2,1,""],append_individual:[5,2,1,""],create_new_individuals:[5,2,1,""],eval_fitness:[5,2,1,""],evaluate_individual:[5,2,1,""],evolve:[5,2,1,""],hypervolume:[5,2,1,""],keep:[5,2,1,""],mate:[5,2,1,""],non_dominated:[5,2,1,""],plot_init_:[5,2,1,""],plot_objectives:[5,2,1,""],update_ideal_and_nadir:[5,2,1,""]},"pyrvea.Problem":{baseProblem:[6,0,0,"-"],testProblem:[6,0,0,"-"]},"pyrvea.Problem.baseProblem":{baseProblem:[6,1,1,""]},"pyrvea.Problem.baseProblem.baseProblem":{constraints:[6,2,1,""],objectives:[6,2,1,""],update:[6,2,1,""]},"pyrvea.Problem.testProblem":{testProblem:[6,1,1,""]},"pyrvea.Problem.testProblem.testProblem":{constraints:[6,2,1,""],objectives:[6,2,1,""]},"pyrvea.Selection":{APD_select:[8,0,0,"-"],NSGAIII_select:[8,0,0,"-"]},"pyrvea.Selection.APD_select":{APD_select:[8,3,1,""]},"pyrvea.Selection.NSGAIII_select":{NSGAIII_select:[8,3,1,""],associate_to_niches:[8,3,1,""],calc_niche_count:[8,3,1,""],calc_perpendicular_distance:[8,3,1,""],get_extreme_points_c:[8,3,1,""],get_nadir_point:[8,3,1,""],niching:[8,3,1,""]},pyrvea:{Recombination:[7,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:function"},terms:{"class":[3,4,5,6,8],"default":[4,5],"float":[3,8],"function":6,"int":[3,4,5,8],"jyv\u00e4skyl\u00e4":[0,3],"new":[5,6],"return":[3,4,5,6,8],"true":[3,4,5],EAs:[1,2],LHS:5,The:[0,3,4,5],Then:4,Use:6,Used:4,Uses:[5,8],a_priori_prefer:3,about:[0,3],accept:[0,6],adapt:4,add:[4,5],add_edge_vector:4,added:5,algorithm:[0,3,4],align:3,alpha:3,also:3,angl:[4,8],angular:8,ani:[0,3],anim:[4,5],animate_2d_init_:4,animate_2d_next_:4,animate_3d_init_:4,animate_3d_next_:4,animate_init_:4,animate_next_:4,animate_parallel_coords_init_:4,animate_parallel_coords_next_:4,apd:3,apd_select:[1,2],append_individu:5,archiv:3,arg:5,arrai:5,assign_typ:5,associate_to_nich:8,base:[3,4,5,6],basedecompositionea:3,baseea:[1,2,5],baseproblem:[1,2,5],basi:8,basic:3,bhupind:[0,3],binari:5,binder:0,bool:[3,4,5],bound:5,calc_niche_count:8,calc_perpendicular_dist:8,calcul:[4,5,6],can:[4,5],chang:3,check:[3,4,5],cheng:[0,3],chosen:5,chugh:4,code:[0,3],compat:4,compromis:3,comput:[0,3],conduct:5,connect:4,consol:4,constraint:[5,6],contact:[0,3],contain:[3,4,5,8],content:[1,2],continu:3,continue_evolut:3,continue_iter:3,coordin:4,core:4,correspond:6,count:5,cover:4,creat:5,create_new_individu:5,creation:5,crossov:5,current:[0,3,4,8],data:4,datafram:4,decis:5,decision_vari:[5,6],decomposit:3,defin:[5,6],deriv:5,describ:[3,5],descript:3,design:5,detail:[0,3,4,8],deviat:8,dict:[3,4,5],differ:[3,4],dimension:4,disabl:3,dist_to_nich:8,distanc:8,ea_paramet:[3,5],each:4,edg:4,enabl:3,entir:[4,5],environ:4,error:5,eval_fit:5,evalu:5,evaluate_individu:5,evolutionari:[0,3,4],evolv:5,exampl:0,extreme_point:8,fals:[3,4],figur:[4,5],file:4,filenam:4,first:4,fit:[4,5,8],fix:5,follow:[0,3,4],found:4,frame:4,from:[3,5,8],gener:[3,4],generations_per_iter:3,genet:3,get_extreme_points_c:8,get_nadir_point:8,guid:[0,3],hack:5,hakanen:4,have:[0,3],higher:4,hypercub:5,hyperspher:4,hypervolum:5,ideal:[3,5,8],ideal_point:8,ieee:[0,3],iii:3,implement:[0,3],ind:5,indic:[3,5,8],individu:[3,4,5,8],inform:[3,4,6],initi:[4,5],intend:4,interact:[0,3,4],interrupt:5,ipynb:0,isnotebook:[1,2],iter:[3,4,5],iteractive_adapt_1:4,jin:[0,3,4],jupyt:4,jussi:4,jyu:[0,3],kaisa:4,karthik:4,keep:5,latin:5,lattic:3,lattice_resolut:[3,4],lhsdesign:5,linearli:4,link:0,list:[3,4,5,6,8],lower_limit:6,mani:[0,3],mate:[5,8],mean:5,mechan:3,method:[5,6],miettinen:4,min:8,minim:[0,5],modul:[1,2],multi:0,multiobject:4,multipli:8,mutat:5,n_nich:8,n_remain:8,n_surviv:8,nadir:5,nadir_point:8,name:[4,6],nd2:5,ndarrai:[4,5],nds:5,need:5,neighbour:4,neighbouring_angl:4,new_objective_v:5,new_pop:5,newli:5,newrv:[1,2],next:4,nich:8,niche_count:8,niche_of_individu:8,non_domin:5,none:[3,5,6,8],normal:4,note:3,notebook:[4,5],nsga:3,nsgaiii:[1,2],nsgaiii_select:[1,2],num_of_constraint:6,num_of_object:6,num_of_vari:6,number:[3,4,5],number_of_object:4,numpi:[4,5],obj:5,object:[0,3,4,5,6],objective_vari:6,olhof:[0,3],onli:4,open:0,optim:[0,3],option:5,orthant:4,othertool:[1,2],over:5,packag:[1,3,5],panda:4,paper:[0,3,4,8],parallel:4,param:3,paramet:[3,4,5,6,8],pass:5,penal:8,penalty_factor:8,per:3,pleas:[0,3],plot:[3,4,5],plot_init_:5,plot_object:5,plotli:4,plotlyanim:[1,2],point:[0,3,4,5,8],polunomi:5,pop_siz:5,popul:[1,2,3,4,8],population_s:3,potenti:3,prefer:[0,4],prevent:5,problem:[1,2,3,5],project:[0,3],provid:[3,4],pygmo:5,pymoo:[3,8],pyrvea:0,python:[0,3],question:[0,3],randomassign:5,randomdesign:5,randomli:5,rather:3,read:0,readm:1,realli:3,recombin:[1,2],ref_dir:8,ref_point:[4,5],refer:[0,3,4,8],referencevector:[1,2,8],remov:5,research:[0,3],resolut:3,row:4,rvea:[0,1,2,8],saini:[0,3],same:5,sampl:[5,6],save:[3,4],scatter:4,see:[0,3,8],select:[1,2,3],self:[3,5],sendhoff:[0,3],sent:5,set:[3,4],set_param:3,should:[3,5],similar:3,simul:5,sindhya:4,size:[3,5],some:5,sourc:[0,3],space:5,str:[4,5],structur:3,submodul:[1,2],support:0,symmetric_vector:[1,2],taken:8,test2:4,test:[0,4],testproblem:[1,2],than:3,thi:[3,5,6],thing:5,tinkl:4,total:3,toward:4,transact:[0,3],translation_param:4,type:[3,4,8],union:4,unit:4,univers:[0,3],updat:[5,6],update_ideal_and_nadir:5,upper_limit:6,useless:3,user:5,uses:3,using:5,utopian_epsilon:8,valu:[4,5,6,8],variabl:5,vector:[0,3,4,8],version:[0,3],violat:[5,6],visual:0,when:4,whether:3,which:[4,5],wors:3,worst_of_front:8,worst_of_popul:8,worst_point:8,yaochu:4,you:[0,3],zeroth:4},titles:["README","Welcome to pyrvea\u2019s documentation!","pyrvea package","pyrvea.EAs","pyrvea.OtherTools","pyrvea.Population","pyrvea.Problem package","pyrvea.Recombination package","pyrvea.Selection package"],titleterms:{EAs:3,apd_select:8,baseea:3,baseproblem:6,content:7,document:1,isnotebook:4,modul:[3,4,5,6,7,8],newrv:4,nsgaiii:3,nsgaiii_select:8,othertool:4,packag:[2,6,7,8],plotlyanim:4,popul:5,problem:6,pyrvea:[1,2,3,4,5,6,7,8],readm:0,recombin:7,referencevector:4,rvea:3,select:8,submodul:[6,8],symmetric_vector:4,testproblem:6,welcom:1}}) \ No newline at end of file +Search.setIndex({docnames:["README","creating_models_example","index","modules","pyrvea","pyrvea.EAs","pyrvea.OtherTools","pyrvea.Population","pyrvea.Problem","pyrvea.Recombination","pyrvea.Selection"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:56},filenames:["README.md","creating_models_example.md","index.rst","modules.rst","pyrvea.rst","pyrvea.EAs.rst","pyrvea.OtherTools.rst","pyrvea.Population.rst","pyrvea.Problem.rst","pyrvea.Recombination.rst","pyrvea.Selection.rst"],objects:{"":{pyrvea:[4,0,0,"-"]},"pyrvea.EAs":{NSGAIII:[5,0,0,"-"],PPGA:[5,0,0,"-"],RVEA:[5,0,0,"-"],TournamentEA:[5,0,0,"-"],baseEA:[5,0,0,"-"],slowRVEA:[5,0,0,"-"]},"pyrvea.EAs.NSGAIII":{NSGAIII:[5,1,1,""]},"pyrvea.EAs.NSGAIII.NSGAIII":{select:[5,2,1,""],set_params:[5,2,1,""]},"pyrvea.EAs.PPGA":{Lattice:[5,1,1,""],PPGA:[5,1,1,""]},"pyrvea.EAs.PPGA.Lattice":{init_predators:[5,2,1,""],init_prey:[5,2,1,""],lattice:[5,3,1,""],lattice_wrap_idx:[5,2,1,""],move_predator:[5,2,1,""],move_prey:[5,2,1,""],neighbours:[5,2,1,""],params:[5,3,1,""],place_offspring:[5,2,1,""],predator_pop:[5,3,1,""],predators_loc:[5,3,1,""],preys_loc:[5,3,1,""],size_x:[5,3,1,""],size_y:[5,3,1,""],update_lattice:[5,2,1,""]},"pyrvea.EAs.PPGA.PPGA":{continue_evolution:[5,2,1,""],continue_iteration:[5,2,1,""],select:[5,2,1,""],set_params:[5,2,1,""]},"pyrvea.EAs.RVEA":{RVEA:[5,1,1,""]},"pyrvea.EAs.RVEA.RVEA":{select:[5,2,1,""],set_params:[5,2,1,""]},"pyrvea.EAs.TournamentEA":{TournamentEA:[5,1,1,""]},"pyrvea.EAs.TournamentEA.TournamentEA":{continue_iteration:[5,2,1,""],select:[5,2,1,""],set_params:[5,2,1,""]},"pyrvea.EAs.baseEA":{BaseDecompositionEA:[5,1,1,""],BaseEA:[5,1,1,""]},"pyrvea.EAs.baseEA.BaseDecompositionEA":{continue_evolution:[5,2,1,""],continue_iteration:[5,2,1,""],select:[5,2,1,""]},"pyrvea.EAs.baseEA.BaseEA":{set_params:[5,2,1,""]},"pyrvea.EAs.slowRVEA":{slowRVEA:[5,1,1,""]},"pyrvea.EAs.slowRVEA.slowRVEA":{set_params:[5,2,1,""]},"pyrvea.OtherTools":{IsNotebook:[6,0,0,"-"],ReferenceVectors:[6,0,0,"-"],newRV:[6,0,0,"-"],plotlyanimate:[6,0,0,"-"],symmetric_vectors:[6,0,0,"-"]},"pyrvea.OtherTools.IsNotebook":{IsNotebook:[6,4,1,""]},"pyrvea.OtherTools.ReferenceVectors":{ReferenceVectors:[6,1,1,""],householder:[6,4,1,""],normalize:[6,4,1,""],rotate:[6,4,1,""],rotate_toward:[6,4,1,""],shear:[6,4,1,""]},"pyrvea.OtherTools.ReferenceVectors.ReferenceVectors":{adapt:[6,2,1,""],add_edge_vectors:[6,2,1,""],iteractive_adapt_1:[6,2,1,""],neighbouring_angles:[6,2,1,""],normalize:[6,2,1,""],slow_interactive_adapt:[6,2,1,""]},"pyrvea.OtherTools.newRV":{dist_based_translation:[6,4,1,""],householder:[6,4,1,""],main:[6,4,1,""],newRV:[6,1,1,""],normalize:[6,4,1,""],rotate:[6,4,1,""]},"pyrvea.OtherTools.newRV.newRV":{interact_v2:[6,2,1,""],interact_v3:[6,2,1,""],project_to_hyperplane:[6,2,1,""],revert_rotation:[6,2,1,""],rotate_to_axis:[6,2,1,""],translate_to_hypersphere:[6,2,1,""]},"pyrvea.OtherTools.plotlyanimate":{animate_2d_init_:[6,4,1,""],animate_2d_next_:[6,4,1,""],animate_3d_init_:[6,4,1,""],animate_3d_next_:[6,4,1,""],animate_init_:[6,4,1,""],animate_next_:[6,4,1,""],animate_parallel_coords_init_:[6,4,1,""],animate_parallel_coords_next_:[6,4,1,""],test2:[6,4,1,""],test:[6,4,1,""]},"pyrvea.OtherTools.symmetric_vectors":{householder:[6,4,1,""],main:[6,4,1,""],normalize:[6,4,1,""],rotate:[6,4,1,""],rotate_toward:[6,4,1,""],shear:[6,4,1,""]},"pyrvea.Population":{Population:[7,0,0,"-"],create_individuals:[7,0,0,"-"]},"pyrvea.Population.Population":{Population:[7,1,1,""]},"pyrvea.Population.Population.Population":{"delete":[7,2,1,""],add:[7,2,1,""],append_individual:[7,2,1,""],eval_fitness:[7,2,1,""],evaluate_individual:[7,2,1,""],evolve:[7,2,1,""],hypervolume:[7,2,1,""],mate:[7,2,1,""],non_dominated:[7,2,1,""],plot_init_:[7,2,1,""],plot_objectives:[7,2,1,""],plot_pareto:[7,2,1,""],update_fitness:[7,2,1,""],update_ideal_and_nadir:[7,2,1,""]},"pyrvea.Population.create_individuals":{create_new_individuals:[7,4,1,""]},"pyrvea.Problem":{baseproblem:[8,0,0,"-"],biogp_problem:[8,0,0,"-"],dataproblem:[8,0,0,"-"],evodn2_problem:[8,0,0,"-"],evonn_problem:[8,0,0,"-"],test_functions:[8,0,0,"-"],testproblem:[8,0,0,"-"]},"pyrvea.Problem.baseproblem":{BaseProblem:[8,1,1,""]},"pyrvea.Problem.baseproblem.BaseProblem":{constraints:[8,2,1,""],objectives:[8,2,1,""],update:[8,2,1,""]},"pyrvea.Problem.biogp_problem":{BioGP:[8,1,1,""],BioGPModel:[8,1,1,""],LinearNode:[8,1,1,""],Node:[8,1,1,""],random:[8,4,1,""]},"pyrvea.Problem.biogp_problem.BioGP":{add:[8,2,1,""],cos:[8,2,1,""],create_individuals:[8,2,1,""],div:[8,2,1,""],log:[8,2,1,""],mul:[8,2,1,""],neg:[8,2,1,""],objectives:[8,2,1,""],select:[8,2,1,""],sin:[8,2,1,""],sqrt:[8,2,1,""],sub:[8,2,1,""],tan:[8,2,1,""]},"pyrvea.Problem.biogp_problem.BioGPModel":{create_logfile:[8,2,1,""],fit:[8,2,1,""],fitness:[8,3,1,""],linear_node:[8,3,1,""],log:[8,3,1,""],minimize:[8,3,1,""],name:[8,3,1,""],plot:[8,2,1,""],predict:[8,2,1,""],set_params:[8,2,1,""],single_variable_response:[8,2,1,""],svr:[8,3,1,""],train:[8,2,1,""]},"pyrvea.Problem.biogp_problem.LinearNode":{calculate_linear:[8,2,1,""]},"pyrvea.Problem.biogp_problem.Node":{draw:[8,2,1,""],draw_tree:[8,2,1,""],get_sub_nodes:[8,2,1,""],grow_tree:[8,2,1,""],node_label:[8,2,1,""],predict:[8,2,1,""]},"pyrvea.Problem.dataproblem":{DataProblem:[8,1,1,""]},"pyrvea.Problem.dataproblem.DataProblem":{data_scaling:[8,2,1,""],data_uniform_mapping:[8,2,1,""],objectives:[8,2,1,""],outlier_removal:[8,2,1,""],retrain_surrogate:[8,2,1,""],surrogates_predict:[8,2,1,""],testing_score:[8,2,1,""],train:[8,2,1,""],train_test_split:[8,2,1,""],transform_new_data:[8,2,1,""]},"pyrvea.Problem.evodn2_problem":{EvoDN2:[8,1,1,""],EvoDN2Model:[8,1,1,""]},"pyrvea.Problem.evodn2_problem.EvoDN2":{activate:[8,2,1,""],activation:[8,2,1,""],calculate_linear:[8,2,1,""],objectives:[8,2,1,""],select:[8,2,1,""]},"pyrvea.Problem.evodn2_problem.EvoDN2Model":{create_logfile:[8,2,1,""],fit:[8,2,1,""],fitness:[8,3,1,""],linear_layer:[8,3,1,""],log:[8,3,1,""],name:[8,3,1,""],non_linear_layer:[8,3,1,""],plot:[8,2,1,""],predict:[8,2,1,""],set_params:[8,2,1,""],single_variable_response:[8,2,1,""],subnets:[8,3,1,""],subsets:[8,3,1,""],svr:[8,3,1,""],train:[8,2,1,""]},"pyrvea.Problem.evonn_problem":{EvoNN:[8,1,1,""],EvoNNModel:[8,1,1,""]},"pyrvea.Problem.evonn_problem.EvoNN":{activate:[8,2,1,""],activation:[8,2,1,""],calculate_linear:[8,2,1,""],information_criterion:[8,2,1,""],objectives:[8,2,1,""],select:[8,2,1,""]},"pyrvea.Problem.evonn_problem.EvoNNModel":{create_logfile:[8,2,1,""],fit:[8,2,1,""],fitness:[8,3,1,""],linear_layer:[8,3,1,""],log:[8,3,1,""],name:[8,3,1,""],non_linear_layer:[8,3,1,""],plot:[8,2,1,""],predict:[8,2,1,""],set_params:[8,2,1,""],single_variable_response:[8,2,1,""],svr:[8,3,1,""],train:[8,2,1,""]},"pyrvea.Problem.test_functions":{OptTestFunctions:[8,1,1,""]},"pyrvea.Problem.test_functions.OptTestFunctions":{create_training_data:[8,2,1,""],objectives:[8,2,1,""]},"pyrvea.Problem.testproblem":{TestProblem:[8,1,1,""]},"pyrvea.Problem.testproblem.TestProblem":{constraints:[8,2,1,""],create_training_data:[8,2,1,""],objectives:[8,2,1,""]},"pyrvea.Recombination":{biogp_mutation:[9,0,0,"-"],biogp_xover:[9,0,0,"-"],bounded_polynomial_mutation:[9,0,0,"-"],evodn2_xover_mutation:[9,0,0,"-"],evonn_xover_mutation:[9,0,0,"-"],simulated_binary_crossover:[9,0,0,"-"]},"pyrvea.Recombination.biogp_mutation":{mutate:[9,4,1,""]},"pyrvea.Recombination.biogp_xover":{mate:[9,4,1,""]},"pyrvea.Recombination.bounded_polynomial_mutation":{mutate:[9,4,1,""]},"pyrvea.Recombination.evodn2_xover_mutation":{mate:[9,4,1,""]},"pyrvea.Recombination.evonn_xover_mutation":{mate:[9,4,1,""]},"pyrvea.Recombination.simulated_binary_crossover":{mate:[9,4,1,""]},"pyrvea.Selection":{APD_select:[10,0,0,"-"],NSGAIII_select:[10,0,0,"-"],tournament_select:[10,0,0,"-"]},"pyrvea.Selection.APD_select":{APD_select:[10,4,1,""]},"pyrvea.Selection.NSGAIII_select":{NSGAIII_select:[10,4,1,""],associate_to_niches:[10,4,1,""],calc_niche_count:[10,4,1,""],calc_perpendicular_distance:[10,4,1,""],get_extreme_points_c:[10,4,1,""],get_nadir_point:[10,4,1,""],niching:[10,4,1,""]},"pyrvea.Selection.tournament_select":{tour_select:[10,4,1,""]},pyrvea:{EAs:[5,0,0,"-"],OtherTools:[6,0,0,"-"],Population:[7,0,0,"-"],Problem:[8,0,0,"-"],Recombination:[9,0,0,"-"],Selection:[10,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function"},terms:{"boolean":[6,7],"case":7,"class":[1,5,6,7,8,10],"default":[1,5,6,7,8,9],"final":[0,1,6,8],"float":[5,6,8,9,10],"function":[0,1,8,9],"g\u00fcnter":[],"import":1,"int":[5,6,7,8,10],"jyv\u00e4skyl\u00e4":[0,5],"new":[0,1,5,6,7,8],"return":[5,6,7,8,9,10],"sax\u00e9n":[0,5,8],"static":[5,8],"switch":0,"true":[0,5,6,8],"try":5,"while":0,EAs:[1,2,3,4,8],For:[1,5,8],LHS:7,The:[0,1,5,6,7,8,9,10],Their:5,Then:[0,6],These:[0,8],Use:8,Used:[6,8],Uses:[6,7,10],Using:[0,1],With:0,a_priori_prefer:5,abl:0,about:[0,5],accept:8,accord:[0,1,5],accuraci:[0,8],achiev:[0,6],activ:[0,8],activated_lay:8,activation_func:8,adapt:6,add:[0,1,6,7,8],add_edge_vector:6,added:[1,7],adding:[0,5],addit:1,address:0,adjust:1,advantag:0,affect:1,after:[0,1,5],again:[0,5],aggreg:8,akaik:8,akaike_correct:8,algorithm:[1,2,5,6,8],algrorithm:0,align:5,all:[0,1,5,7,8,9],alloi:[0,8],allow:[0,8],along:8,alpha:5,also:[0,5,8],alter:0,although:0,amount:6,angl:[6,10],angular:10,ani:[0,5,6],anim:[6,7],animate_2d_init_:6,animate_2d_next_:6,animate_3d_init_:6,animate_3d_next_:6,animate_init_:6,animate_next_:6,animate_parallel_coords_init_:6,animate_parallel_coords_next_:6,ann:8,anoth:9,apd:5,apd_select:[2,3,4],append:7,append_individu:7,appli:[0,5,6,7,8],applic:[0,5,8],approach:[0,5,8],archiv:5,arg:[7,9],ariti:9,around:[0,6],arr:5,arrai:[5,6,8,10],array_lik:[7,8,10],artifici:[7,8],asarrai:1,aspect:5,assign_typ:7,assist:0,associate_to_nich:10,attain:0,attempt:5,attribut:[0,5],avail:[0,1,5],avoid:0,awai:6,axi:[5,6],bad:[0,5],balanc:0,base:[0,5,6,7,8,9],basedecompositionea:5,baseea:[2,3,4,7],baseproblem:[2,3,4,7],basi:[0,5,8,10],basic:[1,5,6],becom:[0,5],bed:[0,8],been:[0,1,5,6,8],befor:8,begin:8,being:0,belong:8,benefit:[0,8],berlin:[0,5],best:[0,1,5,8,10],better:0,between:[0,8,9],bhupind:[0,5,8],bia:[0,8],bias:0,binari:9,biogp:[2,5,8,9],biogp_model:8,biogp_mut:[2,3,4,8],biogp_problem:[2,3,4],biogp_xov:[2,3,4,8],biogpmodel:8,bjectiv:0,blast:[0,5,8],bloat:[0,8],bool:[5,6,7,8],both:[0,1,8],bound:[0,8,9],boundari:8,bounded_polynomial_mut:[2,3,4,7],breed:[5,9],build:0,calc_niche_count:10,calc_perpendicular_dist:10,calcul:[0,6,7,8],calculate_linear:8,call:[0,1],can:[0,1,5,6,7,8],capabl:1,capac:0,captur:0,cell:5,center:[5,6],centr:6,certain:[0,5],chakrabarti:[0,8],chakraborti:[0,5,8],cham:[0,5,8],chang:5,check:[1,5,6,7],chemic:[0,5,8],cheng:5,choos:[0,5,8,9,10],chosen:[7,8],chugh:6,closer:[0,5],code:[0,1,5,8],column:1,combat:[0,8],combin:8,come:0,compat:6,complet:[0,5],complex:[0,8],complexity_scalar:8,composit:0,compromis:5,comput:[0,5,8],concept:0,conduct:7,confer:[0,5],configur:0,conflict:0,connect:[0,6],consist:0,consol:6,constant:[0,1,8],constraint:[7,8],construct:[0,8],contact:[2,5],contain:[0,1,5,6,7,8,9,10],content:[2,3],continu:5,continue_evolut:5,continue_iter:5,contribut:0,control:[0,8],convent:0,converg:0,coordin:[5,6],core:[6,8],correct:[0,8],correspond:8,cos:8,count:[7,8],cover:6,coverag:6,creat:[0,2,5,7,8],create_individu:[2,3,4,8],create_logfil:8,create_new_individu:7,create_training_data:[1,8],creation:[7,8],creation_typ:6,criteria:[0,5],criterion:[0,5,8],cross:[0,5],crossov:[0,5,7,8,9],crossover_typ:[7,8,9],current:[1,5,6,7,8,10],custom:1,data:[0,1,5,6,8],data_decis:8,data_problem:8,data_sc:8,data_uniform_map:8,datafram:[6,8],dataproblem:[1,2,3,4],dataset:[1,8],datta:5,davim:5,deb:[],debalai:[],decis:[7,8],decision_vari:8,decomposit:5,deep:[0,7,8],defin:[0,7,8],degre:6,delet:7,depart:[0,8],depend:[0,1,8],depth:[0,8,9],deriv:7,describ:[5,7],descript:[1,5],design:[0,5,7,8],desir:[5,8],detail:[1,5,6,10],deviat:[9,10],devoid:0,dict:[5,6,7,8,9],dictionari:1,differ:[0,1,5,6],difficult:0,dimension:[5,6],disabl:5,discount:0,dist_based_transl:6,dist_to_nich:10,distanc:[6,10],distribut:5,div:[1,8],divid:8,divis:[0,1],dnn:8,doc:1,document:1,doe:[0,1,7],domain:5,domin:8,done:8,dot:8,draw:8,draw_tre:8,driven:[0,5,8],dure:5,ea_param:[],ea_paramet:[1,5,7,8],each:[0,5,6,8,9,10],earlier:[0,5,8],easili:0,edg:6,eds:5,eep:0,effect:0,effici:0,either:[8,9],element:[5,6],elimin:[0,5],emerg:[0,8],emo:[],emploi:[0,8],empti:5,enabl:5,encod:0,encourag:1,enet:0,engin:[0,5,8],ensur:0,entir:[6,7],entri:9,environ:6,equal:6,error:[0,5,7,8],error_lim:8,essenti:0,etwork:0,eural:0,eval_fit:7,evalu:7,evaluate_individu:7,everi:[0,5],evo:0,evodn2:[2,7,8],evodn2_model:8,evodn2_problem:[2,3,4],evodn2_xover_mut:[2,3,4,8],evodn2model:8,evolut:[0,5,9],evolutionari:[2,5,6,8],evolv:[0,1,7,8],evonn:[2,5,7,8],evonn_model:8,evonn_problem:[2,3,4],evonn_xover_mut:[2,3,4,8],evonnmodel:8,exampl:[0,1],except:6,exclud:7,exist:0,experi:[0,1],expert:8,explan:1,extens:0,extern:8,extreme_point:10,f1_y_pr:1,f2_y_pr:1,f_set:1,fair:9,fals:[5,6,7,8],fare:0,fed:0,feed:0,figur:[0,6,7],file:[6,8],filenam:[1,6,7,8],final_vector:6,find:5,first:[0,6],fit:[0,5,6,7,8,10],fittest:0,fix:[7,8],fleme:1,flexibl:[0,8],fluctuat:0,focu:0,follow:[1,5,6],fonseca:1,footer:8,forward:0,found:[1,5,6],frame:[6,8],free:[0,5],from:[0,1,5,6,7,8,9,10],front:[0,7,8],frontier:0,full:8,function_set:[1,8],furnac:[0,5,8],gaussian:8,gener:[0,5,6,8],generations_per_iter:[1,5],genet:[0,1,5,8,9],get:[0,5,8],get_extreme_points_c:10,get_nadir_point:10,get_sub_nod:8,giri:[0,8],give:8,given:[5,8],greatli:1,grow:[0,8],grow_tre:8,grown:[0,8],guid:5,hack:7,hakanen:[0,6,8],half:8,han:[],hand:[0,5],handl:[0,1,8],happen:0,has:[0,5,6,8],have:[0,1,5,8],header:1,heidelberg:[0,5],height:[5,9],here:[0,1,8],hidden:[0,8],higher:6,household:6,how:[1,8],howev:0,http:8,hunt:[0,5],hypercub:[7,8],hyperplan:6,hyperspher:6,hypervolum:7,ideal:[5,7,8,10],ideal_point:10,ieee:5,iii:5,implement:[0,1,5,8],implicit:0,impliment:5,inact:0,includ:[0,1,7,8],increas:0,ind:[7,8],index:[5,10],indian:[0,8],indic:[5,7,8,9,10],individu:[0,5,6,7,9,10],industri:0,inform:[0,5,6,8],information_criterion:8,init_method:8,init_pred:5,init_prei:5,initi:[5,6,7,8],initial_vector:6,input:[0,8],instanc:8,institut:[0,8],integ:5,intend:6,interact:[5,6],interact_v2:6,interact_v3:6,intern:[0,5],interrupt:7,interv:5,introduc:0,introduct:2,involv:[0,8],isnotebook:[2,3,4],iter:[1,5,6,7],iteractive_adapt_1:6,its:[0,5,8],jin:[5,6],jupyt:6,jussi:6,just:0,jyu:[0,5],kaisa:6,karthik:6,keep:7,kill:[0,5],kill_interv:5,kind:6,kwarg:[5,8],larger:[0,8],last:6,latin:[7,8],lattic:[0,5],lattice_resolut:[5,6],lattice_shap:5,lattice_wrap_idx:5,laumann:[0,5],layer:[0,8],lead:0,learn:0,least:[0,8],lectur:[],length:[6,7],less:[0,8],level:0,lgorithm:0,lhs:8,lhsdesign:7,like:0,limit:0,linear:[0,8],linear_lay:8,linear_nod:8,linearli:[5,6],linearnod:8,list:[1,5,6,7,8,9,10],llsq:[0,8],locat:5,log:[5,8],log_fil:8,logfil:[5,8],loss:8,loss_func:8,lower:[0,5,8,9],lower_limit:[8,9],lowest:0,lutionari:0,lying:6,magnitud:0,mai:0,main:6,major:0,make:[0,6,8],maker:8,mani:[0,5,8],manual:8,map:0,marco:[],master:0,mate:[5,7,9,10],materi:[0,5,8,9],mathemat:[0,8],mating_pop:[5,7,9],matlab:[0,5,8],matric:0,matrix:[6,8],max:[5,8],max_depth:8,max_lay:8,max_nod:8,max_rank:5,max_subtre:8,maximum:8,mean:7,mechan:[0,5,8],meta:8,metaheurist:[0,5,8],metallurg:[0,5,8],method:[5,6,7,8],micro:[0,8],microalloi:0,miettinen:[0,6,8],min:10,min_error:8,min_fit:5,minim:[0,7,8],mixtur:8,mode:0,model:[0,2,5,8],model_paramet:[1,8],model_typ:[1,8],modifi:1,modul:[2,3],mono:9,moor:5,more:[0,5,6,8],move:[0,5,6,8],move_pred:5,move_prei:5,movement:5,much:0,mul:[1,8],multi:[0,5,8],multiobject:[0,5,6],multipl:[0,1,8],multipli:10,mut_strength:5,mutat:[0,5,7,8,9],mutation_typ:[7,8,9],n_nich:10,n_remain:10,n_surviv:10,nadir:[7,8],nadir_point:10,name:[1,6,7,8],natur:[0,5],nd2:7,ndarrai:[5,6,7,8],nds:7,need:[0,5,7],neg:[1,8],neighbour:[5,6],neighbourhood:[0,5],neighbourhood_radiu:5,neighbouring_angl:6,net:[0,5,8],network:[0,7,8],neural:[0,5,7,8],new_objective_v:7,new_pop:7,newli:7,newrv:[2,3,4],next:[0,6],nich:10,niche_count:10,niche_of_individu:10,nijosari:0,niko:[0,5,8],nirupam:[0,5,8],node:[0,8,9],node_label:8,nois:0,noisi:[0,5,8],non:8,non_dom_front:8,non_domin:7,non_linear_lay:8,none:[0,5,6,7,8,9,10],nonlinear:0,nonzero:0,normal:6,note:[1,2,5,8],notebook:[6,7],nsga:5,nsgaiii:[2,3,4],nsgaiii_select:[2,3,4],num_nod:8,num_of_constraint:8,num_of_object:8,num_of_vari:[1,8],num_sampl:8,num_subnet:8,number:[0,5,6,7,8,10],number_of_object:6,numpi:[1,6,7],obj:[7,8],obj_func:8,object:[0,1,5,6,7,8],objective_vari:8,occur:5,off:8,offspr:[5,9],offspring_place_attempt:5,often:0,old_point:5,olhof:5,onc:0,one:[0,5,8,9,10],ones:0,onli:[0,5,6,8],onward:0,oper:[0,8],opt_func:8,opt_param:1,optim:[0,1,5,8],optima:0,option:[1,6,7],opttestfunct:8,org:8,origin:[5,6],orthant:6,other:[0,5,7],other_vector:6,othertool:[2,3,4],otherwis:[6,7,8],out:8,outlier_remov:8,output:[0,8],over:[0,5,7,8],overfit:0,packag:[1,2,3],page:[],panda:[1,6,8],paper:[5,6,10],parallel:[0,5,6],param:[5,7,8,9],paramet:[0,1,5,6,7,8,9,10],parent:[0,5,8,9],pareto:[0,1,5,7],part:[0,8],particip:[5,10],partner:9,pass:[0,1,6,7,8],paul:[],paulo:5,penal:10,penalty_factor:10,per:[5,8],perenni:8,perform:[0,1,8,9],period:5,pettersson:[0,5,8],phase:1,place:[0,5],place_offspr:5,plane:6,pleas:[0,5],plot:[1,5,6,7,8],plot_init_:7,plot_object:7,plot_pareto:[1,7],plotli:6,plotlyanim:[2,3,4],ploton:8,point:[0,5,6,7,8,10],polynomi:9,pop:[1,8,9],pop_siz:[7,8],popul:[0,1,2,3,4,5,6,8,9,10],population_s:5,posit:[5,6],possibl:[0,8],potenti:5,ppga:[1,2,3,4,8],practic:5,pre:0,predat:[0,5],predator_max_mov:5,predator_pop:5,predator_pop_s:5,predatori:5,predators_loc:5,predict:[1,8],predicted_valu:8,prefer:6,prei:[0,5],preject_to_hyperplan:6,preliminari:[0,5],present:0,preserv:[5,7],prevent:7,prey_max_mov:5,preys_loc:5,principl:0,prob_crossov:5,prob_mut:5,prob_omit:8,prob_prey_mov:5,prob_termin:8,probabl:[5,8],problem:[0,1,2,3,4,5,7,9],procedur:8,process:[0,5,8],produc:9,product:[0,8],professor:[0,5,8],program:[0,8],project:[0,5,6],project_to_hyperplan:6,properti:[0,8],provid:[0,5,6],purpos:0,pursu:[0,5],pygmo:7,pymoo:[5,10],pyrvea:1,python:[0,2,5,8],quantif:0,question:[0,5],radian:6,radiu:5,ramp:8,ramped_half_and_half:8,random:[0,1,5,8,9],randomdesign:7,randomli:[5,7,8,9],rang:5,rather:5,ratio:[0,8],reach:[6,8],read_excel:1,real:[0,5],realli:5,receiv:0,recombin:[2,3,4,5,8],recombination_typ:[7,8],recurs:8,redatori:0,reduct:[0,8],ref:6,ref_dir:10,ref_point:[5,6,7],refer:[2,5,6,8,10],referencevector:[2,3,4,10],reflect:6,regrow:9,rei:0,remain:0,remov:[5,7],repeat:5,replac:9,repres:[0,8],reproduc:[0,5],reproduct:[0,5],requir:[0,1],research:[0,5],resolut:5,respect:1,respons:8,result:[6,9],retrain_surrog:8,revers:[6,8],revert_rot:6,rissanen:[0,5,8],roam:[0,5],rogram:0,roi:[],root:[0,1,8],root_mean_squar:8,root_median_squar:8,rotat:6,rotate_to_axi:6,rotate_toward:6,rotated_vector:6,row:6,rudolph:[0,5],run:8,rvea:[0,1,2,3,4,10],saini:[0,5],same:[0,7,8,9],sampl:[1,7,8],save:[5,6,8],scalar:0,scatter:6,schaffer:[],schaffern1:[],schwefel:[0,5],scienc:[],scientif:0,search:[],see:[0,1,5,8,10],seed:8,select:[0,1,2,3,4,5,8,9],self:[5,6,7,8],sendhoff:5,sent:7,separ:8,set:[0,1,5,6,8,9],set_param:[5,8],shape:[5,8],shear:6,should:[0,1,5,6,7,9],show:[1,7,8],show_al:7,shubhabrata:5,siarri:[],sigmoid:8,signifi:[0,5],signific:0,similar:5,similarli:0,simpl:0,simul:[0,8,9],simulated_binary_crossov:[2,3,4,7],sin:8,sindhya:6,singh:[],singl:[0,8],single_obj_gener:8,single_variable_respons:8,situat:0,size:[0,5,7,8],size_i:5,size_x:5,slow:5,slow_interactive_adapt:6,slowli:6,slowrvea:[2,3,4],small:9,smaller:[0,8],soft:[0,5,8],solut:[0,5,7],solv:[0,5],some:[0,7,8],sourc:[0,5],space:7,spatial:[0,5],specif:5,specifi:8,spheric:6,split:1,spot:5,springer:[0,5,8],sqrt:[1,8],squar:[0,1,8],standard:[8,9],start:[0,5,8],steel:[0,8],step:[0,5],stop:5,store:8,str:[6,7,8],strategi:[0,5,8],strength:5,strongli:[],structur:[0,1,5],student:0,studi:[0,5,8],sub:[1,8],submodul:[2,3,4],subnet:[0,8],subpackag:[2,3],subset:[0,8],substract:1,subtre:[0,8,9],succesfulli:0,successfulli:5,sum:[0,8],supervis:[0,5,8],support:8,surrog:[2,8],surrogates_predict:8,svr:8,swagata:[0,8],swap:9,symmetric_vector:[2,3,4],syntax:8,system:[0,5,8],t_set:1,take:[0,8],taken:10,tan:8,target:[1,5,8],target_pop_s:5,target_valu:8,techniqu:[0,8],technolog:[0,8],tell:6,tend:0,term:0,termin:[0,1,8,9],terminal_set:[1,8],test2:6,test:[1,6,8],test_funct:[2,3,4],test_functions_for_optim:8,test_prob:1,testing_scor:8,testproblem:[1,2,3,4],than:[0,5,8],thei:[0,5,8],them:[0,1,5,7],theoret:5,thesi:0,thi:[0,1,5,6,7,8],thiel:[],thing:7,those:7,thousand:0,three:0,through:[0,8],thu:0,tighter:0,tightest:0,tinkl:6,togeth:0,tolist:1,top:0,toroid:5,total:[0,5,8],tour_select:10,tournament:[5,10],tournament_s:[5,10],tournament_select:[2,3,4],tournamentea:[2,3,4],toward:[0,6],trade:8,tradeoff:0,train:[0,1,8],train_siz:[1,8],train_test_split:[1,8],training_algorithm:[1,8],training_data:8,training_error:8,transact:5,transfer:0,transform:6,transform_new_data:8,translat:6,translate_to_hyperspher:6,translation_param:6,tree:[0,8,9],trend:0,tri:5,tupl:[5,8],turn:[0,5],twice:6,two:[0,1,5,9],type:[5,6,7,8,9,10],under:[0,5,8],underfit:0,undetect:0,uniform:6,union:6,unit:6,uniti:6,univers:[0,5],unrepres:0,until:[5,8],updat:[5,7,8],update_fit:7,update_ideal_and_nadir:7,update_lattic:5,upper:[0,8,9],upper_limit:[8,9],use:[0,1,5,8,9],used:[0,1,8,9],useless:5,user:[0,7,8],uses:[0,5,8],using:[0,1,5,7,8],util:0,utopian_epsilon:10,valadi:[],valu:[0,1,6,7,8,9,10],vanadium:0,variabl:[0,1,7,8],variant:5,variou:[0,5],vector:[0,5,6,10],vector_typ:6,veri:0,version:5,via:[0,6],violat:[7,8],vision:5,vol:[],w_high:8,w_low:8,wai:0,walk:[0,5],want:1,weaker:[0,5],weakest:5,weigh:0,weight:[0,8],what:2,when:[0,6,8],where:[0,5,7],wherea:0,whether:[0,5,7],which:[0,1,5,6,7,8],whole:[0,5],whose:5,width:5,wiki:8,wikipedia:8,wise:0,within:[0,5,9],without:0,work:8,workflow:1,wors:5,worst_of_front:10,worst_of_popul:10,worst_point:10,would:0,wrapper:6,written:[0,5,8],x_train:8,xls:1,y_train:8,yaochu:6,you:[0,1,5],your:1,yourself:1,zdt1:1,zdt1_1000:1,zero:[6,8],zeroth:6,zitzler:[]},titles:["Evolutionary algorithms in pyRVEA","Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP","Welcome to pyrvea\u2019s documentation!","pyrvea","pyrvea package","pyrvea.EAs package","pyrvea.OtherTools package","pyrvea.Population package","pyrvea.Problem package","pyrvea.Recombination package","pyrvea.Selection package"],titleterms:{EAs:5,algorithm:0,apd_select:10,baseea:5,baseproblem:8,biogp:[0,1],biogp_mut:9,biogp_problem:8,biogp_xov:9,bounded_polynomial_mut:9,contact:0,content:[4,5,6,7,8,9,10],creat:1,create_individu:7,dataproblem:8,document:2,evodn2:[0,1],evodn2_problem:8,evodn2_xover_mut:9,evolutionari:0,evonn:[0,1],evonn_problem:8,evonn_xover_mut:9,indic:[],introduct:0,isnotebook:6,model:1,modul:[4,5,6,7,8,9,10],newrv:6,note:0,nsgaiii:5,nsgaiii_select:10,othertool:6,packag:[4,5,6,7,8,9,10],plotlyanim:6,popul:7,ppga:[0,5],problem:8,pyrvea:[0,2,3,4,5,6,7,8,9,10],python:1,recombin:9,refer:0,referencevector:6,rvea:5,select:10,simulated_binary_crossov:9,slowrvea:5,submodul:[5,6,7,8,9,10],subpackag:4,surrog:1,symmetric_vector:6,tabl:[],test_funct:8,testproblem:8,tournament_select:10,tournamentea:5,welcom:2,what:0}}) \ No newline at end of file diff --git a/docs/biogp.png b/docs/biogp.png new file mode 100644 index 0000000..ce22ca0 Binary files /dev/null and b/docs/biogp.png differ diff --git a/docs/conf.py b/docs/conf.py index bf212d8..1420d5c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,11 +18,8 @@ # -- Project information ----------------------------------------------------- project = 'pyrvea' -copyright = '2019, Bhupinder Saini' -author = 'Bhupinder Saini' - -# The full version, including alpha/beta/rc tags -release = '0.1' +copyright = '2019, Niko Rissanen, Bhupinder Saini' +author = 'Niko Rissanen, Bhupinder Saini' # -- General configuration --------------------------------------------------- @@ -30,10 +27,8 @@ # 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.napoleon', - 'recommonmark', -] +extensions = ['sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'recommonmark', 'numpydoc'] +autodoc_member_order = 'bysource' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -49,7 +44,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "sphinx_rtd_theme" +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, diff --git a/docs/creating_models_example.md b/docs/creating_models_example.md new file mode 100644 index 0000000..e09b464 --- /dev/null +++ b/docs/creating_models_example.md @@ -0,0 +1,111 @@ +## Creating surrogate models in Python with EvoNN, EvoDN2 and BioGP + +This example will show how to use the code and structure in pyRVEA to create models using EvoNN, EvoDN2 and BioGP ([see descriptions of the algorithms here](https://github.com/delamorte/pyRVEA/blob/master/docs/README.md)). The code is currently capable of training and optimizing the models with all of the genetic algorithms implemented in [pyRVEA/EAs](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). + +The basic workflow is as follows: +1. Create or import training data +2. Create a problem class which handles the training of the models +3. After training, create a new population and evolve it using the models to optimize the problem + +For training data, example functions can be found in pyRVEA/Problem/testproblem.py and test_functions.py packages, or a custom data set can be imported. + +Using [Fonseca-Fleming](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) two objective function with 2 variables as an example: +```python +import numpy as np +import pandas as pd +from pyrvea.Problem.testproblem import TestProblem +from pyrvea.Problem.dataproblem import DataProblem + +test_prob = TestProblem(name="Fonseca-Fleming", num_of_variables=2) + +# Random data for training +# x = list of variable names, y = list of objectives +dataset, x, y = test_prob.create_training_data(samples=500) +``` +Or you can import a data set, here an example data set for [ZDT1](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization) problem with 30 variables and 1000 samples is used. The DataProblem class requires the names of the variables and objectives as lists. If your data set does not contain them in the header, you will have to create them yourself. +``` +dataset = pd.read_excel("ZDT1_1000.xls", header=0) +x = dataset.columns[0:30].tolist() +# x = ['x1', 'x2', 'x3', ...] +y = dataset.columns[30:].tolist() +# y = ['f1', 'f2'] +``` +After you have the data, create the DataProblem class and pass the data, variables and objectives. +``` +problem = DataProblem(data=dataset, x=x, y=y) +``` +You can split the data into a training and testing set: +``` +problem.train_test_split(train_size=0.7) +``` +Parameters can be passed for the model and for the genetic algorithm as dictionaries. If no parameters are passed, the defaults are used. +Select the model and the genetic algorithm you want to use and set the parameters (or use defaults). Check [EA documentation](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html) for details for the genetic algorithms and see docs for [EvoNN parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.evonn_problem.EvoNNModel.set_params), [EvoDN2 parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.evodn2_problem.EvoDN2Model.set_params) and [BioGP parameters](https://htmlpreview.github.io/?https://raw.githubusercontent.com/delamorte/pyRVEA/master/docs/_build/html/pyrvea.Problem.html#pyrvea.Problem.biogp_problem.BioGPModel.set_params). + +Both EA parameters and the model parameters can greatly affect the performance of the model. The best options depend on the problem, so experimenting with different values is encouraged. + +``` +from pyrvea.EAs.PPGA import PPGA + +ea_parameters = { + "generations_per_iteration": 10, + "iterations": 10, +} + +model_parameters = { + "training_algorithm": PPGA +} + +problem.train( + model_type="EvoDN2", + model_parameters=model_parameters, + ea_parameters=ea_parameters) +``` + +Note that for BioGP, function set and terminal should be adjusted according to the problem. By default, function set includes addition, substraction, multiplication and division, and terminal set includes the variables from the data. +For [Fonseca-Fleming function](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization), square root and negative should be added to the function set and constants 1 and 2 to the terminal set: +``` +f_set = ("add", "sub", "mul", "div", "sqrt", "neg") +t_set = [1, 2] + +model_parameters = { + function_set = f_set + terminal_set = t_set +} + +problem.train( + model_type="BioGP", + model_parameters=model_parameters +) +``` + +The models can currently be trained with available algorithms in [pyRVEA/EAs](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). For explanations of the different EAs, see their respective [documentation](https://htmlpreview.github.io/?https://github.com/delamorte/pyRVEA/blob/master/docs/_build/html/pyrvea.EAs.html). + +The model's prediction vs. target values can be plotted as follows: +``` +# Prediction for f1 +f1_y_pred = problem.models["f1"][0].predict(problem.data[problem.x]) + +problem.models["f1"][0].plot( + f1_y_pred, np.asarray(problem.data["f1"]), name="filename" + "f1" +) +# Prediction for f2 +f2_y_pred = problem.models["f2"][0].predict(problem.data[problem.x]) + +problem.models["f2"][0].plot( + f2_y_pred, np.asarray(problem.data["f2"]), name="filename" + "f2" +) +``` + +After the models have been trained, the objectives can be optimized by creating a new population, passing the data problem class (containing the trained models) and calling evolve. EA parameters can be modified for optimization phase if wanted. + +``` +from pyrvea.EAs.RVEA import RVEA + +pop = Population(problem) +opt_params = {"iterations": 10, "generations_per_iteration": 25} +pop.evolve(EA=RVEA, ea_parameters=opt_params) +``` +To show the final pareto plot: +``` +pop.plot_pareto(name="my-test-function") +``` diff --git a/docs/evodn.png b/docs/evodn.png new file mode 100644 index 0000000..d6cb7f8 Binary files /dev/null and b/docs/evodn.png differ diff --git a/docs/evonn.png b/docs/evonn.png new file mode 100644 index 0000000..3801a9e Binary files /dev/null and b/docs/evonn.png differ diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 8016e02..0000000 --- a/docs/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/index.rst b/docs/index.rst index 1dcdf36..2bb3223 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -18,7 +18,7 @@ Welcome to pyrvea's documentation! .. toctree:: :maxdepth: 4 :caption: Contents: - + README.md + creating_models_example.md pyrvea - diff --git a/docs/make.bat b/docs/make.bat index 27f573b..2119f51 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -25,11 +25,11 @@ if errorlevel 9009 ( exit /b 1 ) -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..81819d5 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +pyrvea +====== + +.. toctree:: + :maxdepth: 4 + + pyrvea diff --git a/docs/pyRVEA.EAs.rst b/docs/pyRVEA.EAs.rst deleted file mode 100644 index 7163385..0000000 --- a/docs/pyRVEA.EAs.rst +++ /dev/null @@ -1,26 +0,0 @@ -pyrvea.EAs -================== - -pyrvea.EAs.NSGAIII module -------------------------- - -.. automodule:: pyrvea.EAs.NSGAIII - :members: - :undoc-members: - :show-inheritance: - -pyrvea.EAs.RVEA module ----------------------- - -.. automodule:: pyrvea.EAs.RVEA - :members: - :undoc-members: - :show-inheritance: - -pyrvea.EAs.baseEA module ------------------------- - -.. automodule:: pyrvea.EAs.baseEA - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/pyRVEA.Population.rst b/docs/pyRVEA.Population.rst deleted file mode 100644 index f9e2618..0000000 --- a/docs/pyRVEA.Population.rst +++ /dev/null @@ -1,11 +0,0 @@ -pyrvea.Population -========================= - - -pyrvea.Population.Population module ------------------------------------ - -.. automodule:: pyrvea.Population.Population - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/pyRVEA.Problem.rst b/docs/pyRVEA.Problem.rst deleted file mode 100644 index 7624fff..0000000 --- a/docs/pyRVEA.Problem.rst +++ /dev/null @@ -1,21 +0,0 @@ -pyrvea.Problem package -====================== - -Submodules ----------- - -pyrvea.Problem.baseProblem module ---------------------------------- - -.. automodule:: pyrvea.Problem.baseProblem - :members: - :undoc-members: - :show-inheritance: - -pyrvea.Problem.testProblem module ---------------------------------- - -.. automodule:: pyrvea.Problem.testProblem - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/pyRVEA.Recombination.rst b/docs/pyRVEA.Recombination.rst deleted file mode 100644 index 87cec6a..0000000 --- a/docs/pyRVEA.Recombination.rst +++ /dev/null @@ -1,10 +0,0 @@ -pyrvea.Recombination package -============================ - -Module contents ---------------- - -.. automodule:: pyrvea.Recombination - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/pyRVEA.Selection.rst b/docs/pyRVEA.Selection.rst deleted file mode 100644 index 5b5c45f..0000000 --- a/docs/pyRVEA.Selection.rst +++ /dev/null @@ -1,22 +0,0 @@ -pyrvea.Selection package -======================== - -Submodules ----------- - -pyrvea.Selection.APD\_select module ------------------------------------ - -.. automodule:: pyrvea.Selection.APD_select - :members: - :undoc-members: - :show-inheritance: - -pyrvea.Selection.NSGAIII\_select module ---------------------------------------- - -.. automodule:: pyrvea.Selection.NSGAIII_select - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/pyRVEA.rst b/docs/pyRVEA.rst deleted file mode 100644 index 8962c62..0000000 --- a/docs/pyRVEA.rst +++ /dev/null @@ -1,13 +0,0 @@ -pyrvea package -============== - - -.. toctree:: - - pyrvea.EAs - pyrvea.OtherTools - pyrvea.Population - pyrvea.Problem - pyrvea.Recombination - pyrvea.Selection - diff --git a/docs/pyrvea.EAs.rst b/docs/pyrvea.EAs.rst new file mode 100644 index 0000000..5c8d51b --- /dev/null +++ b/docs/pyrvea.EAs.rst @@ -0,0 +1,62 @@ +pyrvea.EAs package +================== + +Submodules +---------- + +pyrvea.EAs.NSGAIII module +------------------------- + +.. automodule:: pyrvea.EAs.NSGAIII + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.PPGA module +---------------------- + +.. automodule:: pyrvea.EAs.PPGA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.RVEA module +---------------------- + +.. automodule:: pyrvea.EAs.RVEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.TournamentEA module +------------------------------ + +.. automodule:: pyrvea.EAs.TournamentEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.baseEA module +------------------------ + +.. automodule:: pyrvea.EAs.baseEA + :members: + :undoc-members: + :show-inheritance: + +pyrvea.EAs.slowRVEA module +-------------------------- + +.. automodule:: pyrvea.EAs.slowRVEA + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.EAs + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyRVEA.OtherTools.rst b/docs/pyrvea.OtherTools.rst similarity index 59% rename from docs/pyRVEA.OtherTools.rst rename to docs/pyrvea.OtherTools.rst index c89ab07..136cd63 100644 --- a/docs/pyRVEA.OtherTools.rst +++ b/docs/pyrvea.OtherTools.rst @@ -1,44 +1,54 @@ -pyrvea.OtherTools +pyrvea.OtherTools package ========================= +Submodules +---------- pyrvea.OtherTools.IsNotebook module ----------------------------------- .. automodule:: pyrvea.OtherTools.IsNotebook - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.ReferenceVectors module ----------------------------------------- .. automodule:: pyrvea.OtherTools.ReferenceVectors - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.newRV module ------------------------------ .. automodule:: pyrvea.OtherTools.newRV - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.plotlyanimate module -------------------------------------- .. automodule:: pyrvea.OtherTools.plotlyanimate - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: pyrvea.OtherTools.symmetric\_vectors module ------------------------------------------- .. automodule:: pyrvea.OtherTools.symmetric_vectors - :members: - :undoc-members: - :show-inheritance: + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: pyrvea.OtherTools + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyrvea.Population.rst b/docs/pyrvea.Population.rst new file mode 100644 index 0000000..2fc8990 --- /dev/null +++ b/docs/pyrvea.Population.rst @@ -0,0 +1,30 @@ +pyrvea.Population package +========================= + +Submodules +---------- + +pyrvea.Population.Population module +----------------------------------- + +.. automodule:: pyrvea.Population.Population + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Population.create\_individuals module +-------------------------------------------- + +.. automodule:: pyrvea.Population.create_individuals + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Population + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyrvea.Problem.rst b/docs/pyrvea.Problem.rst new file mode 100644 index 0000000..fb6bbe6 --- /dev/null +++ b/docs/pyrvea.Problem.rst @@ -0,0 +1,70 @@ +pyrvea.Problem package +====================== + +Submodules +---------- + +pyrvea.Problem.baseproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.baseproblem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.biogp\_problem module +------------------------------------ + +.. automodule:: pyrvea.Problem.biogp_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.dataproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.dataproblem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.evodn2\_problem module +------------------------------------- + +.. automodule:: pyrvea.Problem.evodn2_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.evonn\_problem module +------------------------------------ + +.. automodule:: pyrvea.Problem.evonn_problem + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.test\_functions module +------------------------------------- + +.. automodule:: pyrvea.Problem.test_functions + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Problem.testproblem module +--------------------------------- + +.. automodule:: pyrvea.Problem.testproblem + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Problem + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyrvea.Recombination.rst b/docs/pyrvea.Recombination.rst new file mode 100644 index 0000000..3ab58c7 --- /dev/null +++ b/docs/pyrvea.Recombination.rst @@ -0,0 +1,62 @@ +pyrvea.Recombination package +============================ + +Submodules +---------- + +pyrvea.Recombination.biogp\_mutation module +------------------------------------------- + +.. automodule:: pyrvea.Recombination.biogp_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.biogp\_xover module +---------------------------------------- + +.. automodule:: pyrvea.Recombination.biogp_xover + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.bounded\_polynomial\_mutation module +--------------------------------------------------------- + +.. automodule:: pyrvea.Recombination.bounded_polynomial_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.evodn2\_xover\_mutation module +--------------------------------------------------- + +.. automodule:: pyrvea.Recombination.evodn2_xover_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.evonn\_xover\_mutation module +-------------------------------------------------- + +.. automodule:: pyrvea.Recombination.evonn_xover_mutation + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Recombination.simulated\_binary\_crossover module +-------------------------------------------------------- + +.. automodule:: pyrvea.Recombination.simulated_binary_crossover + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Recombination + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyrvea.Selection.rst b/docs/pyrvea.Selection.rst new file mode 100644 index 0000000..87ce021 --- /dev/null +++ b/docs/pyrvea.Selection.rst @@ -0,0 +1,38 @@ +pyrvea.Selection package +======================== + +Submodules +---------- + +pyrvea.Selection.APD\_select module +----------------------------------- + +.. automodule:: pyrvea.Selection.APD_select + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Selection.NSGAIII\_select module +--------------------------------------- + +.. automodule:: pyrvea.Selection.NSGAIII_select + :members: + :undoc-members: + :show-inheritance: + +pyrvea.Selection.tournament\_select module +------------------------------------------ + +.. automodule:: pyrvea.Selection.tournament_select + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: pyrvea.Selection + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/pyrvea.rst b/docs/pyrvea.rst new file mode 100644 index 0000000..43d0b0a --- /dev/null +++ b/docs/pyrvea.rst @@ -0,0 +1,22 @@ +pyrvea package +============== + +Subpackages +----------- + +.. toctree:: + + pyrvea.EAs + pyrvea.OtherTools + pyrvea.Population + pyrvea.Problem + pyrvea.Recombination + pyrvea.Selection + +Module contents +--------------- + +.. automodule:: pyrvea + :members: + :undoc-members: + :show-inheritance: diff --git a/evodn.png b/evodn.png new file mode 100644 index 0000000..d6cb7f8 Binary files /dev/null and b/evodn.png differ diff --git a/evodn2_example.py b/evodn2_example.py new file mode 100644 index 0000000..f98cfc2 --- /dev/null +++ b/evodn2_example.py @@ -0,0 +1,110 @@ +from pyrvea.Problem.dataproblem import DataProblem +from pyrvea.Problem.testproblem import TestProblem +from pyrvea.Population.Population import Population +from pyrvea.EAs.PPGA import PPGA +from pyrvea.EAs.RVEA import RVEA +from pyrvea.EAs.slowRVEA import slowRVEA +from pyrvea.EAs.NSGAIII import NSGAIII +import numpy as np +import pandas as pd +from copy import deepcopy +import plotly +import plotly.graph_objs as go + +# test_prob = TestProblem(name="Fonseca-Fleming", num_of_variables=2) +# dataset, x, y = test_prob.create_training_data(samples=500) + +dataset = pd.read_excel("ZDT1_1000.xls", header=0) +x = dataset.columns[0:30].tolist() +y = dataset.columns[30:].tolist() + +problem = DataProblem(data=dataset, x=x, y=y) +problem.train_test_split(train_size=0.7) + +# f_set = ("add", "sub", "mul", "div", "sqrt") +# t_set = [1, 2, 9, 29] +# +# ea_parameters = { +# "generations_per_iteration": 20, +# "iterations": 10, +# +# } +# model_params = { +# "training_algorithm": RVEA, +# "terminal_set": t_set, +# "function_set": f_set, +# "max_depth": 8 +# } +# +# problem.train( +# model_type="BioGP", +# model_parameters=model_params, +# ea_parameters=ea_parameters +# +# ) + +# ea_parameters = { +# "generations_per_iteration": 15, +# "iterations": 10, +# "prob_mutation": 0.7, +# "neighbourhood_radius": 5, +# "target_pop_size": 100, +# "mut_strength": 0.7 +# +# } +# +# model_parameters = { +# "training_algorithm": RVEA, +# +# } +# +# problem.train( +# model_type="EvoDN2", +# model_parameters=model_parameters, +# ea_parameters=ea_parameters +# +# ) + +y_pred = problem.surrogates_predict(problem.data[problem.x]) + +problem.models["f1"][0].plot(y_pred[:, 0], problem.data["f1"], name="ZDT1_1000" + "f1") + +problem.models["f2"][0].plot(y_pred[:, 1], problem.data["f2"], name="ZDT1_1000" + "f2") + +# Optimize +# PPGA +pop_ppga = Population(problem) + +ppga_parameters = { + "prob_prey_move": 0.5, + "prob_mutation": 0.5, + "target_pop_size": 100, + "kill_interval": 4, + "iterations": 10, + "predator_pop_size": 60, + "generations_per_iteration": 10, + "neighbourhood_radius": 5, +} + +pop_ppga.evolve(EA=PPGA, ea_parameters=ppga_parameters) + +pop_ppga.plot_pareto( + name="Tests/" + problem.models["f1"][0].__class__.__name__ + "_ppga_" + "ZDT1_100" +) + +# RVEA +pop_rvea = Population( + problem, + assign_type="LHSDesign", + crossover_type="simulated_binary_crossover", + mutation_type="bounded_polynomial_mutation", + plotting=False, +) + +rvea_parameters = {"iterations": 10, "generations_per_iteration": 25} + +pop_rvea.evolve(EA=RVEA, ea_parameters=rvea_parameters) + +pop_rvea.plot_pareto( + name="Tests/" + problem.models["f1"][0].__class__.__name__ + "_rvea_" + "ZDT1_100" +) \ No newline at end of file diff --git a/evonn.png b/evonn.png new file mode 100644 index 0000000..3801a9e Binary files /dev/null and b/evonn.png differ diff --git a/poetry.lock b/poetry.lock index a1305ff..d52909b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,5 @@ [[package]] -category = "dev" +category = "main" description = "A configurable sidebar-enabled Sphinx theme" name = "alabaster" optional = false @@ -12,7 +12,7 @@ description = "Altair: A declarative statistical visualization library for Pytho name = "altair" optional = false python-versions = "*" -version = "3.0.1" +version = "3.1.0" [package.dependencies] entrypoints = "*" @@ -24,7 +24,7 @@ six = "*" toolz = "*" [[package]] -category = "dev" +category = "main" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" optional = false @@ -63,15 +63,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "19.1.0" [[package]] -category = "dev" +category = "main" description = "Internationalization utilities" name = "babel" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.6.0" +version = "2.7.0" [package.dependencies] -pytz = ">=0a" +pytz = ">=2015.7" [[package]] category = "main" @@ -82,7 +82,7 @@ python-versions = "*" version = "0.1.0" [[package]] -category = "dev" +category = "main" description = "The uncompromising code formatter." name = "black" optional = false @@ -124,7 +124,7 @@ python-versions = "*" version = "3.0.4" [[package]] -category = "dev" +category = "main" description = "Composable command line interface toolkit" name = "click" optional = false @@ -137,7 +137,7 @@ description = "Extended pickling support for Python objects" name = "cloudpickle" optional = false python-versions = "*" -version = "0.8.1" +version = "1.2.1" [[package]] category = "main" @@ -154,11 +154,33 @@ description = "Python parser for the CommonMark Markdown spec" name = "commonmark" optional = false python-versions = "*" -version = "0.8.1" +version = "0.9.0" [package.dependencies] future = "*" +[[package]] +category = "main" +description = "Composable style cycles" +name = "cycler" +optional = false +python-versions = "*" +version = "0.10.0" + +[package.dependencies] +six = "*" + +[[package]] +category = "main" +description = "Distributed Evolutionary Algorithms in Python" +name = "deap" +optional = false +python-versions = "*" +version = "1.3.0" + +[package.dependencies] +numpy = "*" + [[package]] category = "main" description = "Better living through Python with decorators" @@ -188,7 +210,7 @@ numpy = "*" scipy = "*" [[package]] -category = "dev" +category = "main" description = "Docutils -- Python Documentation Utilities" name = "docutils" optional = false @@ -225,6 +247,26 @@ optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" version = "0.17.1" +[[package]] +category = "main" +description = "Genetic Programming in Python, with a scikit-learn inspired API" +name = "gplearn" +optional = false +python-versions = "*" +version = "0.4.1" + +[package.dependencies] +joblib = ">=0.13.0" +scikit-learn = ">=0.20.0" + +[[package]] +category = "main" +description = "Simple Python interface for Graphviz" +name = "graphviz" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +version = "0.11.1" + [[package]] category = "main" description = "Internationalized Domain Names in Applications (IDNA)" @@ -234,7 +276,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.8" [[package]] -category = "dev" +category = "main" description = "Getting image size from png/jpeg/jpeg2000/gif file" name = "imagesize" optional = false @@ -247,7 +289,7 @@ description = "IPython Kernel for Jupyter" name = "ipykernel" optional = false python-versions = ">=3.4" -version = "5.1.0" +version = "5.1.1" [package.dependencies] ipython = ">=5.0.0" @@ -308,7 +350,7 @@ description = "A Python utility / library to sort Python imports." name = "isort" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "4.3.18" +version = "4.3.20" [[package]] category = "main" @@ -332,6 +374,14 @@ version = "2.10.1" [package.dependencies] MarkupSafe = ">=0.23" +[[package]] +category = "main" +description = "Lightweight pipelining: using Python functions as pipeline jobs." +name = "joblib" +optional = false +python-versions = "*" +version = "0.13.2" + [[package]] category = "main" description = "An implementation of JSON Schema validation for Python" @@ -403,13 +453,24 @@ version = "4.4.0" [package.dependencies] traitlets = "*" +[[package]] +category = "main" +description = "A fast implementation of the Cassowary constraint solver" +name = "kiwisolver" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.1.0" + +[package.dependencies] +setuptools = "*" + [[package]] category = "dev" description = "A fast and thorough lazy object proxy." name = "lazy-object-proxy" optional = false -python-versions = "*" -version = "1.3.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.4.1" [[package]] category = "main" @@ -419,6 +480,21 @@ optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" version = "1.1.1" +[[package]] +category = "main" +description = "Python plotting package" +name = "matplotlib" +optional = false +python-versions = ">=3.6" +version = "3.1.1" + +[package.dependencies] +cycler = ">=0.10" +kiwisolver = ">=1.0.1" +numpy = ">=1.11" +pyparsing = ">=2.0.1,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6" +python-dateutil = ">=2.1" + [[package]] category = "dev" description = "McCabe checker, plugin for flake8" @@ -519,7 +595,19 @@ description = "NumPy is the fundamental package for array computing with Python. name = "numpy" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.16.3" +version = "1.16.4" + +[[package]] +category = "main" +description = "Sphinx extension to support docstrings in Numpy format" +name = "numpydoc" +optional = false +python-versions = "*" +version = "0.9.1" + +[package.dependencies] +Jinja2 = ">=2.3" +sphinx = ">=1.6.5" [[package]] category = "main" @@ -530,7 +618,7 @@ python-versions = "*" version = "1.2" [[package]] -category = "dev" +category = "main" description = "Core utilities for Python packages" name = "packaging" optional = false @@ -596,7 +684,7 @@ description = "An open-source, interactive graphing library for Python" name = "plotly" optional = false python-versions = "*" -version = "3.8.1" +version = "3.10.0" [package.dependencies] decorator = ">=4.0.6" @@ -612,7 +700,7 @@ description = "Python client for the Prometheus monitoring system." name = "prometheus-client" optional = false python-versions = "*" -version = "0.6.0" +version = "0.7.0" [[package]] category = "main" @@ -668,8 +756,8 @@ category = "main" description = "Pygments is a syntax highlighting package written in Python." name = "pygments" optional = false -python-versions = "*" -version = "2.3.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.4.2" [[package]] category = "main" @@ -698,7 +786,7 @@ isort = ">=4.2.5,<5" mccabe = ">=0.6,<0.7" [[package]] -category = "dev" +category = "main" description = "Python parsing module" name = "pyparsing" optional = false @@ -711,7 +799,7 @@ description = "Persistent/Functional/Immutable data structures" name = "pyrsistent" optional = false python-versions = "*" -version = "0.15.1" +version = "0.15.2" [package.dependencies] six = "*" @@ -758,7 +846,7 @@ description = "Jupyter Qt console" name = "qtconsole" optional = false python-versions = "*" -version = "4.4.4" +version = "4.5.1" [package.dependencies] ipykernel = ">=4.1" @@ -786,14 +874,14 @@ category = "main" description = "Python HTTP for Humans." name = "requests" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.21.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.22.0" [package.dependencies] certifi = ">=2017.4.17" chardet = ">=3.0.2,<3.1.0" idna = ">=2.5,<2.9" -urllib3 = ">=1.21.1,<1.25" +urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" [[package]] category = "main" @@ -806,16 +894,29 @@ version = "1.3.3" [package.dependencies] six = ">=1.7.0" +[[package]] +category = "main" +description = "A set of python modules for machine learning and data mining" +name = "scikit-learn" +optional = false +python-versions = ">=3.5" +version = "0.21.2" + +[package.dependencies] +joblib = ">=0.11" +numpy = ">=1.11.0" +scipy = ">=0.17.0" + [[package]] category = "main" description = "SciPy: Scientific Library for Python" name = "scipy" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.2.1" +python-versions = ">=3.5" +version = "1.3.0" [package.dependencies] -numpy = ">=1.8.2" +numpy = ">=1.13.3" [[package]] category = "main" @@ -834,7 +935,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*" version = "1.12.0" [[package]] -category = "dev" +category = "main" description = "This package provides 16 stemmer algorithms (15 + Poerter English stemmer) generated from Snowball algorithms." name = "snowballstemmer" optional = false @@ -842,12 +943,12 @@ python-versions = "*" version = "1.2.1" [[package]] -category = "dev" +category = "main" description = "Python documentation generator" name = "sphinx" optional = false python-versions = ">=3.5" -version = "2.0.1" +version = "2.1.2" [package.dependencies] Jinja2 = ">=2.3" @@ -880,7 +981,7 @@ version = "0.4.3" sphinx = "*" [[package]] -category = "dev" +category = "main" description = "" name = "sphinxcontrib-applehelp" optional = false @@ -888,7 +989,7 @@ python-versions = "*" version = "1.0.1" [[package]] -category = "dev" +category = "main" description = "" name = "sphinxcontrib-devhelp" optional = false @@ -896,7 +997,7 @@ python-versions = "*" version = "1.0.1" [[package]] -category = "dev" +category = "main" description = "" name = "sphinxcontrib-htmlhelp" optional = false @@ -904,7 +1005,7 @@ python-versions = "*" version = "1.0.2" [[package]] -category = "dev" +category = "main" description = "A sphinx extension which renders display math in HTML via JavaScript" name = "sphinxcontrib-jsmath" optional = false @@ -912,7 +1013,7 @@ python-versions = ">=3.5" version = "1.0.1" [[package]] -category = "dev" +category = "main" description = "" name = "sphinxcontrib-qthelp" optional = false @@ -920,7 +1021,7 @@ python-versions = "*" version = "1.0.2" [[package]] -category = "dev" +category = "main" description = "" name = "sphinxcontrib-serializinghtml" optional = false @@ -949,7 +1050,7 @@ python-versions = "*" version = "0.4.2" [[package]] -category = "dev" +category = "main" description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false @@ -978,7 +1079,7 @@ description = "Fast, Extensible Progress Meter" name = "tqdm" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "4.31.1" +version = "4.32.1" [[package]] category = "main" @@ -1007,7 +1108,7 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "1.24.2" +version = "1.25.3" [[package]] category = "dev" @@ -1015,7 +1116,7 @@ description = "IPyVega: An IPython/Jupyter widget for Vega 5 and Vega-Lite 3" name = "vega" optional = false python-versions = "*" -version = "2.1.0" +version = "2.2.0" [[package]] category = "dev" @@ -1063,27 +1164,37 @@ optional = false python-versions = "*" version = "1.11.1" +[[package]] +category = "main" +description = "Library for developers to extract data from Microsoft Excel (tm) spreadsheet files" +name = "xlrd" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +version = "1.2.0" + [metadata] -content-hash = "13cd1139829694ce256d34a7e4aae528b7cce70246024a3fe770e6f4bb5e6769" +content-hash = "6d16dc0b27c271b514bed8672a90447a266f44a0075c3aafb3391038dc35899d" python-versions = "^3.6" [metadata.hashes] alabaster = ["446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", "a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"] -altair = ["63934563a7a7b7186335858206a0b9be6043163b8b54a26cd3b3299a9e5e391f", "65e243afa6da5b746c411890fd7dfd0f187c0f8e581cf3c34b07339712cf6627"] +altair = ["77bf6baee04135cc37a20edd07820163336e2d2bb240804473e80dbefcb4bffd", "f711ca44cc569eaec5ae8eafa610146c18b23a0ba4f7b9900646b28c42c13b9f"] appdirs = ["9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92", "d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"] appnope = ["5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0", "8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"] astroid = ["6560e1e1749f68c64a4b5dee4e091fce798d2f0d84ebe638cf0e0585a343acf4", "b65db1bbaac9f9f4d190199bb8680af6f6f84fd3769a5ea883df8a91fe68b4c4"] attrs = ["69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", "f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"] -babel = ["6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669", "8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"] +babel = ["af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab", "e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"] backcall = ["38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4", "bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"] black = ["817243426042db1d36617910df579a54f1afd659adb96fc5032fcf4b36209739", "e030a9a28f542debc08acceb273f228ac422798e5215ba2a791a6ddeaaca22a5"] bleach = ["213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16", "3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"] certifi = ["59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5", "b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"] chardet = ["84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", "fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"] click = ["2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"] -cloudpickle = ["3ea6fd33b7521855a97819b3d645f92d51c8763d3ab5df35197cd8e96c19ba6f", "70b492d5e06b779707c00b334311abcd4ac144c56910068aeeda0079e6244ef0"] +cloudpickle = ["603244e0f552b72a267d47a7d9b347b27a3430f58a0536037a290e7e0e212ecf", "b8ba7e322f2394b9bbbdc1c976e6442c2c02acc784cb9e553cee9186166a6890"] colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] -commonmark = ["9f6dda7876b2bb88dd784440166f4bc8e56cb2b2551264051123bacb0b6c1d8a", "abcbc854e0eae5deaf52ae5e328501b78b4a0758bf98ac8bb792fce993006084"] +commonmark = ["14c3df31e8c9c463377e287b2a1eefaa6019ab97b22dad36e2f32be59d61d68d", "867fc5db078ede373ab811e16b6789e9d033b15ccd7296f370ca52d1ee792ce0"] +cycler = ["1d8a5ae1ff6c5cf9b93e8811e581232ad8920aeec647c37316ceac982b08cb2d", "cd7b2d1018258d7247a71425e9f26463dfb444d411c39569972f4ce586b0c9d8"] +deap = ["01ab6067af3c86bd3a00a0d5e0c9860220c7cf412031f9cce18a6d08ec25b808", "0dc11a5521f661a7c7f475466d932b056fbfee8447ad73b007d69ef75c924355", "11162ae0343a25f5a8625f683ce16bad5757812d71db6b80a5ac7c25799a1a88", "1873f5e2a55ff61dac965b55cc042b2fe5529edbd54fc0fc1061664ddb4b75db", "19f6a60c91313cb1f39a9687bc54efab8abc599e5f81b87faedf583efc388602", "21787af1e4a56345bbffa6d1b07f5611d3ef7b299e5e832e6ab28dbab5c5c10e", "2f50f38ae0c82554a476d6c6013c85da4a8d7cac102edc4ec460a658200bd832", "31ed6220068e703d3f54c53046b8f25b85a9225c64e1e50172c2172c4bd8a7fe", "34594ba2f417ccb622b0ff54c25850fde80e12ca89fde6f242b15029e846be29", "3603c91779c276588884321637212511962b2f0668cec56b2b5664d28f28eee7", "5ee3cee4eac683237915bf570ede65047224ac6f392970fed029e3404935647c", "600e95e745cee25fda8c9a67219c9f46c4661da636a5af9f5e924230e7a3aeac", "6102d8bca425ff5d704f7631b69c22e33782e33020ce059cc88085746444ebfe", "669840720da9c4571efd9d0efdf90267009686b7a4c43dd4ab124e33e9cc153a", "6c5ef3b6c387cd28c7aab0297b05a9994b9c88dfd8a89236866c14703d55f9dc", "a0a0e56bd52a262ee12f84fa883b7ec5367532b784e2a6e83b1f7126b69d2300", "a1cc5fc4a2735ec5560ddef84f80beb84540d3221a147b53bba5e6a8718c8a55", "b05f607041c3f8aac5364055cb9632714bc62fe93e53283fbafea9ba91e13a69", "cd0fd7bccf7837b9e6a666b75e1c3a629fa3f5bc346cb90a9edd8cd56f085980", "cf1e53c822526bbc418333c47f668f394b00b51fddb4f15c54d5f190b2b88f17", "e648e1d76d5c8ecbce7f312bd174e4d2613debddd81f2a614b9023f7ad0331a0", "f146a9a0957510b57a2b5c669a26f0b84b2d219000b5684f4827884a75ad2ea7", "f1a0d1390e0b4f9edd4cbf2903c7d60865f43bad00de239aa066ffeda4ad7ee0", "fe789aa74ba78549030037dc9580510ff1763ef12fdf05cb92dda74237110565"] decorator = ["86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de", "f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6"] defusedxml = ["6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93", "f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"] diversipy = ["6abc959e64821c7122137c4352a7c9d45217a26feb2b4d4830d627b0c82b04d4"] @@ -1091,22 +1202,27 @@ docutils = ["02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] flake8 = ["859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", "a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"] future = ["67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8"] +gplearn = ["6caf620291a2c9ad769483be6b08ada2ae1951b20d69ecd53ed839d2e77c5da4", "8b439e8337132ad5eb111aa9c30126c1b62299ce66468b9e23f9d0885ec1126f"] +graphviz = ["6d0f69c107cfdc9bd1df3763fad99569bbcba29d0c52ffcbc6f266621d8bf709", "914b8b124942d82e3e1dcef499c9fe77c10acd3d18a1cfeeb2b9de05f6d24805"] idna = ["c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"] imagesize = ["3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8", "f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"] -ipykernel = ["0aeb7ec277ac42cc2b59ae3d08b10909b2ec161dc6908096210527162b53675d", "0fc0bf97920d454102168ec2008620066878848fcfca06c22b669696212e292f"] +ipykernel = ["346189536b88859937b5f4848a6fd85d1ad0729f01724a411de5cae9b618819c", "f0e962052718068ad3b1d8bcc703794660858f58803c3798628817f492a8769c"] ipython = ["54c5a8aa1eadd269ac210b96923688ccf01ebb2d0f21c18c3c717909583579a8", "e840810029224b56cd0d9e7719dc3b39cf84d577f8ac686547c8ba7a06eeab26"] ipython-genutils = ["72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", "eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"] ipywidgets = ["0f2b5cde9f272cb49d52f3f0889fdd1a7ae1e74f37b48dac35a83152780d2b7b", "a3e224f430163f767047ab9a042fc55adbcab0c24bbe6cf9f306c4f89fdf0ba3"] -isort = ["1349c6f7c2a0f7539f5f2ace51a9a8e4a37086ce4de6f78f5f53fb041d0a3cd5", "f09911f6eb114e5592abe635aded8bf3d2c3144ebcfcaf81ee32e7af7b7d1870"] +isort = ["c40744b6bc5162bbb39c1257fe298b7a393861d50978b565f3ccd9cb9de0182a", "f57abacd059dc3bd666258d1efb0377510a89777fda3e3274e3c01f7c03ae22d"] jedi = ["2bb0603e3506f708e792c7f4ad8fc2a7a9d9c2d292a358fbbd58da531695595b", "2c6bcd9545c7d6440951b12b44d373479bf18123a401a52025cf98563fbd826c"] jinja2 = ["065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"] +joblib = ["21e0c34a69ad7fde4f2b1f3402290e9ec46f545f15f1541c582edfe05d87b63a", "315d6b19643ec4afd4c41c671f9f2d65ea9d787da093487a81ead7b0bac94524"] jsonschema = ["0c0a81564f181de3212efa2d17de1910f8732fa1b71c42266d983cd74304e20d", "a5f6559964a3851f59040d3b961de5e68e70971afb88ba519d27e6a039efff1a"] jupyter = ["3e1f86076bbb7c8c207829390305a2b1fe836d471ed54be66a3b8c41e7f46cc7", "5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78", "d9dc4b3318f310e34c82951ea5d6683f67bed7def4b259fafbfe4f1beb1d8e5f"] jupyter-client = ["b5f9cb06105c1d2d30719db5ffb3ea67da60919fb68deaefa583deccd8813551", "c44411eb1463ed77548bc2d5ec0d744c9b81c4a542d9637c7a52824e2121b987"] jupyter-console = ["308ce876354924fb6c540b41d5d6d08acfc946984bf0c97777c1ddcb42e0b2f5", "cc80a97a5c389cbd30252ffb5ce7cefd4b66bde98219edd16bf5cb6f84bb3568"] jupyter-core = ["927d713ffa616ea11972534411544589976b2493fc7e09ad946e010aa7eb9970", "ba70754aa680300306c699790128f6fbd8c306ee5927976cbe48adacf240c0b7"] -lazy-object-proxy = ["0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", "1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", "209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", "27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", "27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", "2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", "2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", "320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", "50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", "5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", "61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", "6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", "7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", "7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", "7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", "7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", "81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", "933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", "94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", "ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", "bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", "cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", "d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", "ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", "e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", "e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", "e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", "eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", "f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b"] +kiwisolver = ["05b5b061e09f60f56244adc885c4a7867da25ca387376b02c1efc29cc16bcd0f", "26f4fbd6f5e1dabff70a9ba0d2c4bd30761086454aa30dddc5b52764ee4852b7", "3b2378ad387f49cbb328205bda569b9f87288d6bc1bf4cd683c34523a2341efe", "400599c0fe58d21522cae0e8b22318e09d9729451b17ee61ba8e1e7c0346565c", "47b8cb81a7d18dbaf4fed6a61c3cecdb5adec7b4ac292bddb0d016d57e8507d5", "53eaed412477c836e1b9522c19858a8557d6e595077830146182225613b11a75", "58e626e1f7dfbb620d08d457325a4cdac65d1809680009f46bf41eaf74ad0187", "5a52e1b006bfa5be04fe4debbcdd2688432a9af4b207a3f429c74ad625022641", "5c7ca4e449ac9f99b3b9d4693debb1d6d237d1542dd6a56b3305fe8a9620f883", "682e54f0ce8f45981878756d7203fd01e188cc6c8b2c5e2cf03675390b4534d5", "79bfb2f0bd7cbf9ea256612c9523367e5ec51d7cd616ae20ca2c90f575d839a2", "7f4dd50874177d2bb060d74769210f3bce1af87a8c7cf5b37d032ebf94f0aca3", "8944a16020c07b682df861207b7e0efcd2f46c7488619cb55f65882279119389", "8aa7009437640beb2768bfd06da049bad0df85f47ff18426261acecd1cf00897", "939f36f21a8c571686eb491acfffa9c7f1ac345087281b412d63ea39ca14ec4a", "9733b7f64bd9f807832d673355f79703f81f0b3e52bfce420fc00d8cb28c6a6c", "a02f6c3e229d0b7220bd74600e9351e18bc0c361b05f29adae0d10599ae0e326", "a0c0a9f06872330d0dd31b45607197caab3c22777600e88031bfe66799e70bb0", "acc4df99308111585121db217681f1ce0eecb48d3a828a2f9bbf9773f4937e9e", "b64916959e4ae0ac78af7c3e8cef4becee0c0e9694ad477b4c6b3a536de6a544", "d3fcf0819dc3fea58be1fd1ca390851bdb719a549850e708ed858503ff25d995", "d52e3b1868a4e8fd18b5cb15055c76820df514e26aa84cc02f593d99fef6707f", "db1a5d3cc4ae943d674718d6c47d2d82488ddd94b93b9e12d24aabdbfe48caee", "e3a21a720791712ed721c7b95d433e036134de6f18c77dbe96119eaf7aa08004", "e8bf074363ce2babeb4764d94f8e65efd22e6a7c74860a4f05a6947afc020ff2", "f16814a4a96dc04bf1da7d53ee8d5b1d6decfc1a92a63349bb15d37b6a263dd9", "f2b22153870ca5cf2ab9c940d7bc38e8e9089fa0f7e5856ea195e1cf4ff43d5a", "f790f8b3dff3d53453de6a7b7ddd173d2e020fb160baff578d578065b108a05f"] +lazy-object-proxy = ["159a745e61422217881c4de71f9eafd9d703b93af95618635849fe469a283661", "23f63c0821cc96a23332e45dfaa83266feff8adc72b9bcaef86c202af765244f", "3b11be575475db2e8a6e11215f5aa95b9ec14de658628776e10d96fa0b4dac13", "3f447aff8bc61ca8b42b73304f6a44fa0d915487de144652816f950a3f1ab821", "4ba73f6089cd9b9478bc0a4fa807b47dbdb8fad1d8f31a0f0a5dbf26a4527a71", "4f53eadd9932055eac465bd3ca1bd610e4d7141e1278012bd1f28646aebc1d0e", "64483bd7154580158ea90de5b8e5e6fc29a16a9b4db24f10193f0c1ae3f9d1ea", "6f72d42b0d04bfee2397aa1862262654b56922c20a9bb66bb76b6f0e5e4f9229", "7c7f1ec07b227bdc561299fa2328e85000f90179a2f44ea30579d38e037cb3d4", "7c8b1ba1e15c10b13cad4171cfa77f5bb5ec2580abc5a353907780805ebe158e", "8559b94b823f85342e10d3d9ca4ba5478168e1ac5658a8a2f18c991ba9c52c20", "a262c7dfb046f00e12a2bdd1bafaed2408114a89ac414b0af8755c696eb3fc16", "acce4e3267610c4fdb6632b3886fe3f2f7dd641158a843cf6b6a68e4ce81477b", "be089bb6b83fac7f29d357b2dc4cf2b8eb8d98fe9d9ff89f9ea6012970a853c7", "bfab710d859c779f273cc48fb86af38d6e9210f38287df0069a63e40b45a2f5c", "c10d29019927301d524a22ced72706380de7cfc50f767217485a912b4c8bd82a", "dd6e2b598849b3d7aee2295ac765a578879830fb8966f70be8cd472e6069932e", "e408f1eacc0a68fed0c08da45f31d0ebb38079f043328dce69ff133b95c29dc1"] markupsafe = ["00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"] +matplotlib = ["1febd22afe1489b13c6749ea059d392c03261b2950d1d45c17e3aed812080c93", "31a30d03f39528c79f3a592857be62a08595dec4ac034978ecd0f814fa0eec2d", "4442ce720907f67a79d45de9ada47be81ce17e6c2f448b3c64765af93f6829c9", "796edbd1182cbffa7e1e7a97f1e141f875a8501ba8dd834269ae3cd45a8c976f", "934e6243df7165aad097572abf5b6003c77c9b6c480c3c4de6f2ef1b5fdd4ec0", "bab9d848dbf1517bc58d1f486772e99919b19efef5dd8596d4b26f9f5ee08b6b", "c1fe1e6cdaa53f11f088b7470c2056c0df7d80ee4858dadf6cbe433fcba4323b", "e5b8aeca9276a3a988caebe9f08366ed519fff98f77c6df5b64d7603d0e42e36", "ec6bd0a6a58df3628ff269978f4a4b924a0d371ad8ce1f8e2b635b99e482877a"] mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] mistune = ["59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e", "88a1051873018da288eee8538d476dffe1262495144b33ecb586c4ab266bb8d4"] mypy = ["2afe51527b1f6cdc4a5f34fc90473109b22bf7f21086ba3e9451857cf11489e6", "56a16df3e0abb145d8accd5dbb70eba6c4bd26e2f89042b491faa78c9635d1e2", "5764f10d27b2e93c84f70af5778941b8f4aa1379b2430f85c827e0f5464e8714", "5bbc86374f04a3aa817622f98e40375ccb28c4836f36b66706cf3c6ccce86eda", "6a9343089f6377e71e20ca734cd8e7ac25d36478a9df580efabfe9059819bf82", "6c9851bc4a23dc1d854d3f5dfd5f20a016f8da86bcdbb42687879bb5f86434b0", "b8e85956af3fcf043d6f87c91cbe8705073fc67029ba6e22d3468bfee42c4823", "b9a0af8fae490306bc112229000aa0c2ccc837b49d29a5c42e088c132a2334dd", "bbf643528e2a55df2c1587008d6e3bda5c0445f1240dfa85129af22ae16d7a9a", "c46ab3438bd21511db0f2c612d89d8344154c0c9494afc7fbc932de514cf8d15", "f7a83d6bd805855ef83ec605eb01ab4fa42bcef254b13631e451cbb44914a9b0"] @@ -1114,7 +1230,8 @@ mypy-extensions = ["37e0e956f41369209a3d5f34580150bcacfabaa57b33a15c0b25f4b5725e nbconvert = ["138381baa41d83584459b5cfecfc38c800ccf1f37d9ddd0bd440783346a4c39c", "4a978548d8383f6b2cfca4a3b0543afb77bc7cb5a96e8b424337ab58c12da9bc"] nbformat = ["b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", "f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402"] notebook = ["573e0ae650c5d76b18b6e564ba6d21bf321d00847de1d215b418acb64f056eb8", "f64fa6624d2323fbef6210a621817d6505a45d0d4a9367f1843b20a38a4666ee"] -numpy = ["0e2eed77804b2a6a88741f8fcac02c5499bba3953ec9c71e8b217fad4912c56c", "1c666f04553ef70fda54adf097dbae7080645435fc273e2397f26bbf1d127bbb", "1f46532afa7b2903bfb1b79becca2954c0a04389d19e03dc73f06b039048ac40", "315fa1b1dfc16ae0f03f8fd1c55f23fd15368710f641d570236f3d78af55e340", "3d5fcea4f5ed40c3280791d54da3ad2ecf896f4c87c877b113576b8280c59441", "48241759b99d60aba63b0e590332c600fc4b46ad597c9b0a53f350b871ef0634", "4b4f2924b36d857cf302aec369caac61e43500c17eeef0d7baacad1084c0ee84", "54fe3b7ed9e7eb928bbc4318f954d133851865f062fa4bbb02ef8940bc67b5d2", "5a8f021c70e6206c317974c93eaaf9bc2b56295b6b1cacccf88846e44a1f33fc", "754a6be26d938e6ca91942804eb209307b73f806a1721176278a6038869a1686", "771147e654e8b95eea1293174a94f34e2e77d5729ad44aefb62fbf8a79747a15", "78a6f89da87eeb48014ec652a65c4ffde370c036d780a995edaeb121d3625621", "7fde5c2a3a682a9e101e61d97696687ebdba47637611378b4127fe7e47fdf2bf", "80d99399c97f646e873dd8ce87c38cfdbb668956bbc39bc1e6cac4b515bba2a0", "88a72c1e45a0ae24d1f249a529d9f71fe82e6fa6a3fd61414b829396ec585900", "a4f4460877a16ac73302a9c077ca545498d9fe64e6a81398d8e1a67e4695e3df", "a61255a765b3ac73ee4b110b28fccfbf758c985677f526c2b4b39c48cc4b509d", "ab4896a8c910b9a04c0142871d8800c76c8a2e5ff44763513e1dd9d9631ce897", "abbd6b1c2ef6199f4b7ca9f818eb6b31f17b73a6110aadc4e4298c3f00fab24e", "b16d88da290334e33ea992c56492326ea3b06233a00a1855414360b77ca72f26", "b78a1defedb0e8f6ae1eb55fa6ac74ab42acc4569c3a2eacc2a407ee5d42ebcb", "cfef82c43b8b29ca436560d51b2251d5117818a8d1fb74a8384a83c096745dad", "d160e57731fcdec2beda807ebcabf39823c47e9409485b5a3a1db3a8c6ce763e"] +numpy = ["0778076e764e146d3078b17c24c4d89e0ecd4ac5401beff8e1c87879043a0633", "141c7102f20abe6cf0d54c4ced8d565b86df4d3077ba2343b61a6db996cefec7", "14270a1ee8917d11e7753fb54fc7ffd1934f4d529235beec0b275e2ccf00333b", "27e11c7a8ec9d5838bc59f809bfa86efc8a4fd02e58960fa9c49d998e14332d5", "2a04dda79606f3d2f760384c38ccd3d5b9bb79d4c8126b67aff5eb09a253763e", "3c26010c1b51e1224a3ca6b8df807de6e95128b0908c7e34f190e7775455b0ca", "52c40f1a4262c896420c6ea1c6fda62cf67070e3947e3307f5562bd783a90336", "6e4f8d9e8aa79321657079b9ac03f3cf3fd067bf31c1cca4f56d49543f4356a5", "7242be12a58fec245ee9734e625964b97cf7e3f2f7d016603f9e56660ce479c7", "7dc253b542bfd4b4eb88d9dbae4ca079e7bf2e2afd819ee18891a43db66c60c7", "94f5bd885f67bbb25c82d80184abbf7ce4f6c3c3a41fbaa4182f034bba803e69", "a89e188daa119ffa0d03ce5123dee3f8ffd5115c896c2a9d4f0dbb3d8b95bfa3", "ad3399da9b0ca36e2f24de72f67ab2854a62e623274607e37e0ce5f5d5fa9166", "b0348be89275fd1d4c44ffa39530c41a21062f52299b1e3ee7d1c61f060044b8", "b5554368e4ede1856121b0dfa35ce71768102e4aa55e526cb8de7f374ff78722", "cbddc56b2502d3f87fda4f98d948eb5b11f36ff3902e17cb6cc44727f2200525", "d79f18f41751725c56eceab2a886f021d70fd70a6188fd386e29a045945ffc10", "dc2ca26a19ab32dc475dbad9dfe723d3a64c835f4c23f625c2b6566ca32b9f29", "dd9bcd4f294eb0633bb33d1a74febdd2b9018b8b8ed325f861fffcd2c7660bb8", "e8baab1bc7c9152715844f1faca6744f2416929de10d7639ed49555a85549f52", "ec31fe12668af687b99acf1567399632a7c47b0e17cfb9ae47c098644ef36797", "f12b4f7e2d8f9da3141564e6737d79016fe5336cc92de6814eba579744f65b0a", "f58ac38d5ca045a377b3b377c84df8175ab992c970a53332fa8ac2373df44ff7"] +numpydoc = ["e08f8ee92933e324ff347771da15e498dbf0bc6295ed15003872b34654a0a627"] optproblems = ["0c3c8fcc0a13deb83da4ff3388cdf0d48e1be32ccda6aec4656bc73707c10407"] packaging = ["0c98a5d0be38ed775798ece1b9727178c4469d9c3b4ada66e8e6b7849f8732af", "9e1cbf8c12b1f1ce0bb5344b8d7ecf66a6f8a6e91bcb0c84593ed6d3ab5c4ab3"] pandas = ["071e42b89b57baa17031af8c6b6bbd2e9a5c68c595bc6bf9adabd7a9ed125d3b", "17450e25ae69e2e6b303817bdf26b2cd57f69595d8550a77c308be0cd0fd58fa", "17916d818592c9ec891cbef2e90f98cc85e0f1e89ed0924c9b5220dc3209c846", "2538f099ab0e9f9c9d09bbcd94b47fd889bad06dc7ae96b1ed583f1dc1a7a822", "366f30710172cb45a6b4f43b66c220653b1ea50303fbbd94e50571637ffb9167", "42e5ad741a0d09232efbc7fc648226ed93306551772fc8aecc6dce9f0e676794", "4e718e7f395ba5bfe8b6f6aaf2ff1c65a09bb77a36af6394621434e7cc813204", "4f919f409c433577a501e023943e582c57355d50a724c589e78bc1d551a535a2", "4fe0d7e6438212e839fc5010c78b822664f1a824c0d263fd858f44131d9166e2", "5149a6db3e74f23dc3f5a216c2c9ae2e12920aa2d4a5b77e44e5b804a5f93248", "627594338d6dd995cfc0bacd8e654cd9e1252d2a7c959449228df6740d737eb8", "83c702615052f2a0a7fb1dd289726e29ec87a27272d775cb77affe749cca28f8", "8c872f7fdf3018b7891e1e3e86c55b190e6c5cee70cab771e8f246c855001296", "90f116086063934afd51e61a802a943826d2aac572b2f7d55caaac51c13db5b5", "a3352bacac12e1fc646213b998bce586f965c9d431773d9e91db27c7c48a1f7d", "bcdd06007cca02d51350f96debe51331dec429ac8f93930a43eb8fb5639e3eb5", "c1bd07ebc15285535f61ddd8c0c75d0d6293e80e1ee6d9a8d73f3f36954342d0", "c9a4b7c55115eb278c19aa14b34fcf5920c8fe7797a09b7b053ddd6195ea89b3", "cc8fc0c7a8d5951dc738f1c1447f71c43734244453616f32b8aa0ef6013a5dfb", "d7b460bc316064540ce0c41c1438c416a40746fd8a4fb2999668bf18f3c4acf1"] @@ -1122,31 +1239,32 @@ pandocfilters = ["b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0d parso = ["17cc2d7a945eb42c3569d4564cdf49bde221bc2b552af3eca9c1aad517dcdd33", "2e9574cb12e7112a87253e14e2c380ce312060269d04bd018478a3c92ea9a376"] pexpect = ["2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1", "9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"] pickleshare = ["87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca", "9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"] -plotly = ["04708425517a7bdf4855976b8f91b647282104b3419bd097ff42655238793a4f", "51eb88e82dc2221cf3cf84f5bf5a348597358e57285e436436baaee7e0a7f436"] -prometheus-client = ["1b38b958750f66f208bcd9ab92a633c0c994d8859c831f7abc1f46724fcee490"] +plotly = ["5dcb33f5c9a00e1d68ac567340b58e90c07ba93767ad3e360dd6aa11cf568a98", "ab51c41f3212c5b50238abc1be070cdf79dea60a127216e7c2f1829d14113b49"] +prometheus-client = ["ee0c90350595e4a9f36591f291e6f9933246ea67d7cd7d1d6139a9781b14eaae"] prompt-toolkit = ["11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780", "2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1", "977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55"] ptyprocess = ["923f299cc5ad920c68f2bc0bc98b75b9f838b93b599941a6b63ddbc2476394c0", "d7cc528d76e76342423ca640335bd3633420dc1366f258cb31d05e865ef5ca1f"] pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] pydoe = ["cbd6f14ae26d3c9f736013205f53ea1191add4567033c3ee77b7dd356566c4b6"] pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] -pygments = ["5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a", "e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"] +pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"] pygmo = ["071475f9ed61455793cff864822863273e97742a70c4026d42ccb7fb972b56e0", "0fe3f296244810ee0c05f0a6f608dd809a649b268f5e5056e09993aa535c6a7a", "1ed06a6a9fdc380d31a27cbed0a81fef17df07a61989daa6cdb1b5b3b400a026", "3730104a58362899edf2bb8b05b869f7be3d368efcc3309c20f1a2470dbc914c", "6e94e79db38a5003dc7f22e02fd7262530865e2b13feb9c75fe25bb5eb1b6701", "8a4ae264bd585bf592de3cb96ce327ffb774efabd4bb6cfee7ddd2741ab8b908", "e1e193e98c68b9aee40e87765fd8cb13ae5a44ba863c471c8b501f9d7a3e7c05", "f773d0b004ff04cfda238e5a60f9e3dcb251445495e6bf1363f939654379dc6c"] pylint = ["5d77031694a5fb97ea95e828c8d10fc770a1df6eb3906067aaed42201a8a6a09", "723e3db49555abaf9bf79dc474c6b9e2935ad82230b10c1138a71ea41ac0fff1"] pyparsing = ["1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", "9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"] -pyrsistent = ["5403d37f4d55ff4572b5b5676890589f367a9569529c6f728c11046c4ea4272b"] +pyrsistent = ["16692ee739d42cf5e39cef8d27649a8c1fdb7aa99887098f1460057c5eb75c3a"] python-dateutil = ["7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb", "c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"] pytz = ["303879e36b721603cc54604edcac9d20401bdbe31e1e4fdee5b9f98d5d31dfda", "d747dd3d23d77ef44c6a3526e274af6efeb0a6f1afd5a69ba4d5be4098c8e141"] pywinpty = ["0e01321e53a230233358a6d608a1a8bc86c3882cf82769ba3c62ca387dc9cc51", "333e0bc5fca8ad9e9a1516ebedb2a65da38dc1f399f8b2ea57d6cccec1ff2cc8", "3ca3123aa6340ab31bbf9bd012b92e72f9ec905e4c9ee152cc997403e1778cd3", "44a6dddcf2abf402e22f87e2c9a341f7d0b296afbec3d28184c8de4d7f514ee4", "53d94d574c3d4da2df5b1c3ae728b8d90e4d33502b0388576bbd4ddeb4de0f77", "c3955f162c53dde968f3fc11361658f1d83b683bfe601d4b6f94bb01ea4300bc", "cec9894ecb34de3d7b1ca121dd98433035b9f8949b5095e84b103b349231509c", "dcd45912e2fe2e6f72cee997a4da6ed1ad2056165a277ce5ec7f7ac98dcdf667", "f2bcdd9a2ffd8b223752a971b3d377fb7bfed85f140ec9710f1218d760f2ccb7"] pyzmq = ["1651e52ed91f0736afd6d94ef9f3259b5534ce8beddb054f3d5ca989c4ef7c4f", "5ccb9b3d4cd20c000a9b75689d5add8cd3bce67fcbd0f8ae1b59345247d803af", "5e120c4cd3872e332fb35d255ad5998ebcee32ace4387b1b337416b6b90436c7", "5e2a3707c69a7281a9957f83718815fd74698cba31f6d69f9ed359921f662221", "63d51add9af8d0442dc90f916baf98fdc04e3b0a32afec4bfc83f8d85e72959f", "65c5a0bdc49e20f7d6b03a661f71e2fda7a99c51270cafe71598146d09810d0d", "66828fabe911aa545d919028441a585edb7c9c77969a5fea6722ef6e6ece38ab", "7d79427e82d9dad6e9b47c0b3e7ae5f9d489b1601e3a36ea629bb49501a4daf3", "824ee5d3078c4eae737ffc500fbf32f2b14e6ec89b26b435b7834febd70120cf", "89dc0a83cccec19ff3c62c091e43e66e0183d1e6b4658c16ee4e659518131494", "8b319805f6f7c907b101c864c3ca6cefc9db8ce0791356f180b1b644c7347e4c", "90facfb379ab47f94b19519c1ecc8ec8d10813b69d9c163117944948bdec5d15", "a0a178c7420021fc0730180a914a4b4b3092ce9696ceb8e72d0f60f8ce1655dd", "a7a89591ae315baccb8072f216614b3e59aed7385aef4393a6c741783d6ee9cf", "ba2578f0ae582452c02ed9fac2dc477b08e80ce05d2c0885becf5fff6651ccb0", "c69b0055c55702f5b0b6b354133e8325b9a56dbc80e1be2d240bead253fb9825", "ca434e1858fe222380221ddeb81e86f45522773344c9da63c311d17161df5e06", "d4b8ecfc3d92f114f04d5c40f60a65e5196198b827503341521dda12d8b14939", "d706025c47b09a54f005953ebe206f6d07a22516776faa4f509aaff681cc5468", "d8f27e958f8a2c0c8ffd4d8855c3ce8ac3fa1e105f0491ce31729aa2b3229740", "dbd264298f76b9060ce537008eb989317ca787c857e23cbd1b3ddf89f190a9b1", "e926d66f0df8fdbf03ba20583af0f215e475c667fb033d45fd031c66c63e34c9", "efc3bd48237f973a749f7312f68062f1b4ca5c2032a0673ca3ea8e46aa77187b", "f59bc782228777cbfe04555707a9c56d269c787ed25d6d28ed9d0fbb41cb1ad2", "f8da5322f4ff5f667a0d5a27e871b560c6637153c81e318b35cb012b2a98835c"] -qtconsole = ["a667558c7b1e1442a2e5bcef1686c55e096efd0b58d8b2a0a8415f4579991ee3", "fdfc6002d9d2834c88f9c92e0f6f590284ff3740fa53016f188a62d58bcca6d8"] +qtconsole = ["4af84facdd6f00a6b9b2927255f717bb23ae4b7a20ba1d9ef0a5a5a8dbe01ae2", "60d61d93f7d67ba2b265c6d599d413ffec21202fec999a952f658ff3a73d252b"] recommonmark = ["a520b8d25071a51ae23a27cf6252f2fe387f51bdc913390d83b2b50617f5bb48", "c85228b9b7aea7157662520e74b4e8791c5eacd375332ec68381b52bf10165be"] -requests = ["502a824f31acdacb3a35b6690b5fbf0bc41d63a24a45c4004352b0242707598e", "7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"] +requests = ["11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"] retrying = ["08c039560a6da2fe4f2c426d0766e284d3b736e355f8dd24b37367b0bb41973b"] -scipy = ["014cb900c003b5ac81a53f2403294e8ecf37aedc315b59a6b9370dce0aa7627a", "281a34da34a5e0de42d26aed692ab710141cad9d5d218b20643a9cb538ace976", "588f9cc4bfab04c45fbd19c1354b5ade377a8124d6151d511c83730a9b6b2338", "5a10661accd36b6e2e8855addcf3d675d6222006a15795420a39c040362def66", "628f60be272512ca1123524969649a8cb5ae8b31cca349f7c6f8903daf9034d7", "6dcc43a88e25b815c2dea1c6fac7339779fc988f5df8396e1de01610604a7c38", "70e37cec0ac0fe95c85b74ca4e0620169590fd5d3f44765f3c3a532cedb0e5fd", "7274735fb6fb5d67d3789ddec2cd53ed6362539b41aa6cc0d33a06c003aaa390", "78e12972e144da47326958ac40c2bd1c1cca908edc8b01c26a36f9ffd3dce466", "790cbd3c8d09f3a6d9c47c4558841e25bac34eb7a0864a9def8f26be0b8706af", "79792c8fe8e9d06ebc50fe23266522c8c89f20aa94ac8e80472917ecdce1e5ba", "865afedf35aaef6df6344bee0de391ee5e99d6e802950a237f9fb9b13e441f91", "870fd401ec7b64a895cff8e206ee16569158db00254b2f7157b4c9a5db72c722", "963815c226b29b0176d5e3d37fc9de46e2778ce4636a5a7af11a48122ef2577c", "9726791484f08e394af0b59eb80489ad94d0a53bbb58ab1837dcad4d58489863", "9de84a71bb7979aa8c089c4fb0ea0e2ed3917df3fb2a287a41aaea54bbad7f5d", "b2c324ddc5d6dbd3f13680ad16a29425841876a84a1de23a984236d1afff4fa6", "b86ae13c597fca087cb8c193870507c8916cefb21e52e1897da320b5a35075e5", "ba0488d4dbba2af5bf9596b849873102d612e49a118c512d9d302ceafa36e01a", "d78702af4102a3a4e23bb7372cec283e78f32f5573d92091aa6aaba870370fe1", "def0e5d681dd3eb562b059d355ae8bebe27f5cc455ab7c2b6655586b63d3a8ea", "e085d1babcb419bbe58e2e805ac61924dac4ca45a07c9fa081144739e500aa3c", "e2cfcbab37c082a5087aba5ff00209999053260441caadd4f0e8f4c2d6b72088", "e742f1f5dcaf222e8471c37ee3d1fd561568a16bb52e031c25674ff1cf9702d5", "f06819b028b8ef9010281e74c59cb35483933583043091ed6b261bb1540f11cc", "f15f2d60a11c306de7700ee9f65df7e9e463848dbea9c8051e293b704038da60", "f31338ee269d201abe76083a990905473987371ff6f3fdb76a3f9073a361cf37", "f6b88c8d302c3dac8dff7766955e38d670c82e0d79edfc7eae47d6bb2c186594"] +scikit-learn = ["051c53f9e900b0e9eccff2391f5317d1673d72e842bcbcd3e5d0b132459086ed", "0aafc312a55ebf58073151b9308761a5fcfa45b7f7730cea4b1f066f824c72db", "185d88ee4955cd68d7ff57356d1dd99cfc2de4b6aa5e5d679cafbc9df54716ff", "195465c39daded4f3ef8759291ffde81365486d4293e63dd9e32de0f569ecbbf", "4a6398500d035a4402476a2e3ae9f65a7a3f1b366ec6a7f6dd45c289f72dc954", "56f14e98632fb9237e7d005c6d8e346d01fa67f7b92f5f5d57a0bd06c741f9f6", "77092513dd780e12affde46a6394b52947db3fc00cf1d8c1c8eede52b37591d1", "7d2cdfe16b1ae6f9a1760b69be27c2004a84fc362984f930df135c847c47b765", "82c3450fc375f27e3529fa05fec627c9fc75915e05fcd55de43f193b3aa907af", "a5fba00d9037b62b0e0906f64efe9e4a754e556bc091cc12f84bc81655b4a414", "acba6bf5928e415b6296799a7aa069b66254c9440bce88ed2e5915865a317093", "b474f00d2533f18761fb17fb0950b27e72baf0796176247b5a7cf0ee369790ee", "ca45e0def97f73a828cee417174fafa0ab35a41f8bdca4424120a29c5589c548", "f09e544a6756afbd9d31e1d8ddfde5a2c9c17f6d4274104c988fceb611e2d5c5", "f979bb85cbfd9ed4d54709d86ab8893b316726abd1c9ab04abe7e6414b71b753", "fb4c7a2294447515fffec33c1f5eedbe942e9be56edb8c6619607e7882531d40"] +scipy = ["03b1e0775edbe6a4c64effb05fff2ce1429b76d29d754aa5ee2d848b60033351", "09d008237baabf52a5d4f5a6fcf9b3c03408f3f61a69c404472a16861a73917e", "10325f0ffac2400b1ec09537b7e403419dcd25d9fee602a44e8a32119af9079e", "1db9f964ed9c52dc5bd6127f0dd90ac89791daa690a5665cc01eae185912e1ba", "409846be9d6bdcbd78b9e5afe2f64b2da5a923dd7c1cd0615ce589489533fdbb", "4907040f62b91c2e170359c3d36c000af783f0fa1516a83d6c1517cde0af5340", "6c0543f2fdd38dee631fb023c0f31c284a532d205590b393d72009c14847f5b1", "826b9f5fbb7f908a13aa1efd4b7321e36992f5868d5d8311c7b40cf9b11ca0e7", "a7695a378c2ce402405ea37b12c7a338a8755e081869bd6b95858893ceb617ae", "a84c31e8409b420c3ca57fd30c7589378d6fdc8d155d866a7f8e6e80dec6fd06", "adadeeae5500de0da2b9e8dd478520d0a9945b577b2198f2462555e68f58e7ef", "b283a76a83fe463c9587a2c88003f800e08c3929dfbeba833b78260f9c209785", "c19a7389ab3cd712058a8c3c9ffd8d27a57f3d84b9c91a931f542682bb3d269d", "c3bb4bd2aca82fb498247deeac12265921fe231502a6bc6edea3ee7fe6c40a7a", "c5ea60ece0c0c1c849025bfc541b60a6751b491b6f11dd9ef37ab5b8c9041921", "db61a640ca20f237317d27bc658c1fc54c7581ff7f6502d112922dc285bdabee"] send2trash = ["60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", "f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b"] six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] snowballstemmer = ["919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128", "9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"] -sphinx = ["423280646fb37944dd3c85c58fb92a20d745793a9f6c511f59da82fa97cd404b", "de930f42600a4fef993587633984cc5027dedba2464bcf00ddace26b40f8d9ce"] +sphinx = ["22538e1bbe62b407cf5a8aabe1bb15848aa66bb79559f42f5202bbce6b757a69", "f9a79e746b87921cabc3baa375199c6076d1270cee53915dbd24fdbeaaacc427"] sphinx-rtd-theme = ["00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4", "728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"] sphinxcontrib-applehelp = ["edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897", "fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"] sphinxcontrib-devhelp = ["6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34", "9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"] @@ -1159,13 +1277,14 @@ testpath = ["46c89ebb683f473ffe2aab0ed9f12581d4d078308a3cb3765d79c6b2317b0109", toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] toolz = ["929f0a7ea7f61c178bd951bdae93920515d3fbdbafc8e6caf82d752b9b3b31c9"] tornado = ["1174dcb84d08887b55defb2cda1986faeeea715fff189ef3dc44cce99f5fca6b", "2613fab506bd2aedb3722c8c64c17f8f74f4070afed6eea17f20b2115e445aec", "44b82bc1146a24e5b9853d04c142576b4e8fa7a92f2e30bc364a85d1f75c4de2", "457fcbee4df737d2defc181b9073758d73f54a6cfc1f280533ff48831b39f4a8", "49603e1a6e24104961497ad0c07c799aec1caac7400a6762b687e74c8206677d", "8c2f40b99a8153893793559919a355d7b74649a11e59f411b0b0a1793e160bc0", "e1d897889c3b5a829426b7d52828fb37b28bc181cd598624e65c8be40ee3f7fa"] -tqdm = ["d385c95361699e5cf7622485d9b9eae2d4864b21cd5a2374a9c381ffed701021", "e22977e3ebe961f72362f6ddfb9197cc531c9737aaf5f607ef09740c849ecd05"] +tqdm = ["0a860bf2683fdbb4812fe539a6c22ea3f1777843ea985cb8c3807db448a0f7ab", "e288416eecd4df19d12407d0c913cbf77aa8009d7fddb18f632aded3bdbdda6b"] traitlets = ["9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835", "c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"] typed-ast = ["132eae51d6ef3ff4a8c47c393a4ef5ebf0d1aecc96880eb5d6c8ceab7017cc9b", "18141c1484ab8784006c839be8b985cfc82a2e9725837b0ecfa0203f71c4e39d", "2baf617f5bbbfe73fd8846463f5aeafc912b5ee247f410700245d68525ec584a", "3d90063f2cbbe39177e9b4d888e45777012652d6110156845b828908c51ae462", "4304b2218b842d610aa1a1d87e1dc9559597969acc62ce717ee4dfeaa44d7eee", "4983ede548ffc3541bae49a82675996497348e55bafd1554dc4e4a5d6eda541a", "5315f4509c1476718a4825f45a203b82d7fdf2a6f5f0c8f166435975b1c9f7d4", "6cdfb1b49d5345f7c2b90d638822d16ba62dc82f7616e9b4caa10b72f3f16649", "7b325f12635598c604690efd7a0197d0b94b7d7778498e76e0710cd582fd1c7a", "8d3b0e3b8626615826f9a626548057c5275a9733512b137984a68ba1598d3d2f", "8f8631160c79f53081bd23446525db0bc4c5616f78d04021e6e434b286493fd7", "912de10965f3dc89da23936f1cc4ed60764f712e5fa603a09dd904f88c996760", "b010c07b975fe853c65d7bbe9d4ac62f1c69086750a574f6292597763781ba18", "c908c10505904c48081a5415a1e295d8403e353e0c14c42b6d67f8f97fae6616", "c94dd3807c0c0610f7c76f078119f4ea48235a953512752b9175f9f98f5ae2bd", "ce65dee7594a84c466e79d7fb7d3303e7295d16a83c22c7c4037071b059e2c21", "eaa9cfcb221a8a4c2889be6f93da141ac777eb8819f077e1d09fb12d00a09a93", "f3376bc31bad66d46d44b4e6522c5c21976bf9bca4ef5987bb2bf727f4506cbb", "f9202fa138544e13a4ec1a6792c35834250a85958fde1251b6a22e07d1260ae7"] -urllib3 = ["4c291ca23bbb55c76518905869ef34bdd5f0e46af7afe6861e8375643ffee1a0", "9a247273df709c4fedb38c711e44292304f73f39ab01beda9f6b9fc375669ac3"] -vega = ["abb93e4af0f97b4ca7a5034bc1c358b9863ece536b4b9c9707551011b7e65053"] +urllib3 = ["b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"] +vega = ["4d7269756a190edb8e99ce9ce225bc7609d4c124e9fdf89c0a6c6d77ca7ade1d"] vega-datasets = ["20d490b417f84607eb5079400f608f2e9c135b7092bee10f6857f6d23136e459", "63d6eaf129ab23a7d0744e54d11dba9e7eecc0974fd9a237cfae9cfdbef3c37a"] wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] webencodings = ["a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", "b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"] widgetsnbextension = ["14b2c65f9940c9a7d3b70adbe713dbd38b5ec69724eebaba034d1036cf3d4740", "fa618be8435447a017fd1bf2c7ae922d0428056cfc7449f7a8641edf76b48265"] wrapt = ["4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"] +xlrd = ["546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2", "e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"] diff --git a/pyproject.toml b/pyproject.toml index 3e93adf..b4efc9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,15 @@ pyDOE = "^0.3.8" plotly = "^3.8" tqdm = "^4.31" jupyter = "^1.0" +scikit-learn = "^0.21.2" +black = {version = "^18.3-alpha.0",allows-prereleases = true} +matplotlib = "^3.1" +sphinx = "^2.1" +deap = "^1.3" +gplearn = "^0.4.1" +graphviz = "^0.11.1" +xlrd = "^1.2" +numpydoc = "^0.9.1" [tool.poetry.dev-dependencies] flake8 = "^3.7" diff --git a/pyrvea/EAs/NSGAIII.py b/pyrvea/EAs/NSGAIII.py index 47dc279..7b75eba 100644 --- a/pyrvea/EAs/NSGAIII.py +++ b/pyrvea/EAs/NSGAIII.py @@ -21,11 +21,14 @@ def set_params( population: "Population", population_size: int = None, lattice_resolution: int = None, - interact: bool = True, + interact: bool = False, a_priori_preference: bool = False, - generations_per_iteration: int = 100, + generations_per_iteration: int = 10, iterations: int = 10, plotting: bool = True, + logging: bool = False, + logfile = None, + **kwargs ): lattice_resolution_options = { "2": 49, @@ -55,11 +58,16 @@ def set_params( "generations": generations_per_iteration, "iterations": iterations, "ploton": plotting, + "logging": logging, + "logfile": logfile, "current_iteration_gen_count": 0, "current_iteration_count": 0, + "current_total_gen_count": 0, + "total_generations": iterations * generations_per_iteration, "reference_vectors": reference_vectors, "extreme_points": None, } + nsga3params.update(kwargs) return nsga3params def select(self, population: "Population"): diff --git a/pyrvea/EAs/PPGA.py b/pyrvea/EAs/PPGA.py new file mode 100644 index 0000000..3495393 --- /dev/null +++ b/pyrvea/EAs/PPGA.py @@ -0,0 +1,583 @@ +from random import choice, sample +import numpy as np +from pyrvea.Population.Population import Population +from pygmo import fast_non_dominated_sorting as nds + + +class PPGA: + """Predatory-Prey genetic algorithm. + + A population of prey signify the various models or solutions to the problem at hand. + Weaker prey, i.e. bad models or solutions, are killed by predators. + The predators and prey are placed in a lattice, in which they are free to roam. + + In each generation, each predator gets a certain number of turns to move about and hunt + in its neighbourhood, killing the weaker prey, according to a fitness criteria. After this, each + prey gets a certain number of moves to pursue a random walk and to reproduce with + other prey. Each reproduction step generates two new prey from two parents, by + crossing over their attributes and adding random mutations. After each prey has + completed its move, the whole process starts again. + + As the weaker individuals get eliminated in each generation, the population as a whole becomes more fit, + i.e. the individuals get closer to the true pareto-optimal solutions. + + If you have any questions about the code, please contact: + + Bhupinder Saini: bhupinder.s.saini@jyu.fi + Project researcher at University of Jyväskylä. + + Parameters + ---------- + population : object + The population object + ea_parameters : dict + PPGA specific parameters + + Notes + ----- + The algorithm has been created earlier in MATLAB, and this Python implementation has been using + that code as a basis. + See references [4] for the study during which the original MATLAB version was created. + Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + + For the MATLAB implementation, see: + N. Chakraborti. Data-Driven Bi-Objective Genetic Algorithms EvoNN and BioGP and Their Applications in Metallurgical + and Materials Domain. In Datta, Shubhabrata, Davim, J. Paulo (eds.), Computational Approaches to + Materials Design: Theoretical and Practical Aspects, pp. 346-369, 2016. + + References + ---------- + [1] Laumanns, M., Rudolph, G., & Schwefel, H. P. (1998). A spatial predator-prey approach to multi-objective + optimization: A preliminary study. + In International Conference on Parallel Problem Solving from Nature (pp. 241-249). Springer, Berlin, Heidelberg. + + [2] Li, X. (2003). A real-coded predator-prey genetic algorithm for multiobjective optimization. In International + Conference on Evolutionary Multi-Criterion Optimization (pp. 207-221). Springer, Berlin, Heidelberg. + + [3] Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. + In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham. + + [4] Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net + applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397. + + """ + + def __init__(self, population: "Population", ea_parameters): + + if ea_parameters: + self.params = self.set_params(population, **ea_parameters) + else: + self.params = self.set_params(population) + + self.lattice = Lattice(60, 60, self.params) + + def set_params( + self, + population: "Population", + target_pop_size: int = 100, + predator_pop_size: int = 50, + prey_max_moves: int = 10, + prob_prey_move: float = 0.3, + offspring_place_attempts: int = 10, + generations_per_iteration: int = 10, + iterations: int = 10, + kill_interval: int = 7, + max_rank: int = 20, + prob_crossover: float = 0.8, + prob_mutation: float = 0.3, + mut_strength: float = 0.9, + neighbourhood_radius: int = 3, + **kwargs + ): + """Set up the parameters. + + Parameters + ---------- + population : Population + Population object. + target_pop_size : int + Target population size. + predator_pop_size : int + Predator population size. + prey_max_moves : int + Number of turns the prey can try to move. + prob_prey_move: float + Prey move in the lattice based on this probability. + offspring_place_attempts : int + Number of tries to place to offspring to the lattice. + generations_per_iteration : int + Number of generations per iteration. + iterations : int + Total number of iterations. + kill_interval : int + Kill all individuals worse than max_rank in the population every interval generation. + max_rank : int + Individuals < max_rank will be preserved after kill_interval. + prob_crossover : float + Probability of crossover occurring. + prob_mutation : float + Probability of mutation occurring. + mut_strength : float + Strength of the mutation. + neighbourhood_radius : int + Radius of neighbourhood, or range of vision for predators. + + Returns + ------- + dict + Parameters for the algorithm. + + """ + + ppgaparams = { + "population": population, + "population_size": population.pop_size, + "target_pop_size": target_pop_size, + "predator_pop_size": predator_pop_size, + "prey_max_moves": prey_max_moves, + "prob_prey_move": prob_prey_move, + "offspring_place_attempts": offspring_place_attempts, + "generations": generations_per_iteration, + "iterations": iterations, + "total_generations": iterations * generations_per_iteration, + "current_iteration_gen_count": 0, + "current_total_gen_count": 0, + "current_iteration_count": 0, + "prob_crossover": prob_crossover, + "prob_mutation": prob_mutation, + "mut_strength": mut_strength, + "kill_interval": kill_interval, + "max_rank": max_rank, + "neighbourhood_radius": neighbourhood_radius, + } + + ppgaparams.update(kwargs) + return ppgaparams + + def _next_iteration(self, population: "Population"): + """Run one iteration of EA. + + One iteration consists of a constant or variable number of + generations. + + Parameters + ---------- + population : "Population" + Contains current population + """ + + self.params["current_iteration_gen_count"] = 1 + while self.continue_iteration(): + self._next_gen(population) + self.params["current_iteration_gen_count"] += 1 + self.params["current_total_gen_count"] += 1 + self.params["current_iteration_count"] += 1 + + def _next_gen(self, population: "Population"): + """Run one generation of PPGA. + + Intended to be used by next_iteration. + + Parameters + ---------- + population: "Population" + Population object + """ + + # Move prey and select neighbours for breeding + mating_pop = self.lattice.move_prey() + + offspring = population.mate(mating_pop, self.params) + + # Try to place the offspring to lattice, add to population if successful + placed_indices = self.lattice.place_offspring(len(offspring)) + + # Remove from offsprings the ones that didn't get placed + mask = np.ones(len(offspring), dtype=bool) + mask[placed_indices] = False + offspring = np.asarray(offspring)[~mask] + + # Add the successfully placed offspring to the population + population.add(offspring) + + # Kill bad individuals every n generations + if ( + self.params["current_iteration_gen_count"] % self.params["kill_interval"] + == 0 + ): + selected = self.select(population, self.params["max_rank"]) + self.lattice.update_lattice(selected) + population.delete(selected) + + # Move predators + self.lattice.move_predator() + + def _run_interruption(self, population: "Population"): + """Run the interruption phase of PPGA. + + Use this phase to make changes to PPGA.params or other objects. + + Parameters + ---------- + population : Population + """ + + pass + + def select(self, population, max_rank=20) -> list: + """Of the population, individuals lower than max_rank are selected. + Return indices of selected individuals. + + Parameters + ---------- + population : Population + Contains the current population and problem + information. + max_rank : int + Select only individuals lower than max_rank + + Returns + ------- + list + List of indices of individuals to be selected. + """ + # Calculating fronts and ranks + _, _, _, rank = nds(population.fitness) + selection = np.nonzero(rank > max_rank) + return selection[0] + + def continue_iteration(self): + """Checks whether the current iteration should be continued or not.""" + return self.params["current_iteration_gen_count"] <= self.params["generations"] + + def continue_evolution(self) -> bool: + """Checks whether the current iteration should be continued or not.""" + pass + + +class Lattice: + """The 2-dimensional toroidal lattice in which the predators and prey are placed. + + Attributes + ---------- + size_x : int + Width of the lattice. + size_y : int + Height of the lattice. + lattice : ndarray + 2d array for the lattice. + predator_pop : ndarray + The predator population. + predators_loc : list + Location (x, y) of predators on the lattice. + preys_loc : list + Location (x, y) of preys on the lattice. + params : dict + Parameters for the algorithm + + """ + + def __init__(self, size_x, size_y, params): + + self.size_x = size_x + self.size_y = size_y + self.lattice = np.zeros((self.size_y, self.size_x), int) + self.predator_pop = np.empty((0, 1)) + self.predators_loc = [] + self.preys_loc = [] + self.mating_pop = [] + self.params = params + self.init_predators() + self.init_prey() + + def init_predators(self): + """Initialize the predator population, linearly distributed in [0,1] + and place them in the lattice randomly.""" + + # Initialize the predator population + self.predator_pop = np.linspace(0, 1, num=self.params["predator_pop_size"]) + + # Take random indices from free (==zero) lattice spaces + free_space = np.transpose(np.nonzero(self.lattice == 0)) + indices = sample(free_space.tolist(), self.predator_pop.shape[0]) + + for i in range(self.predator_pop.shape[0]): + + # Keep track of predator locations in a list + self.predators_loc.append([indices[i][0], indices[i][1]]) + + # +1 to offset zero index individual, set negative number to + # identify predators from prey in the lattice + self.lattice[indices[i][0]][indices[i][1]] = int(-1 * (i + 1)) + + def init_prey(self): + """Find an empty position in the lattice and place the prey.""" + + # Take random indices from free (==zero) lattice spaces + free_space = np.transpose(np.nonzero(self.lattice == 0)) + indices = sample( + free_space.tolist(), len(self.params["population"].individuals) + ) + + for i in range(len(self.params["population"].individuals)): + + # Keep track of preys in a list + self.preys_loc.append([indices[i][0], indices[i][1]]) + + # +1 to offset zero index individual + self.lattice[indices[i][0]][indices[i][1]] = int(i + 1) + + def move_prey(self): + """Find an empty position in prey neighbourhood for the prey to move in, + and choose a mate for breeding if any available. + + Returns + ------- + mating_pop : list + List of parent indices to use for mating + """ + mating_pop = [] + for prey, pos in enumerate(self.preys_loc): + + if np.random.random() < self.params["prob_prey_move"]: + + for i in range(self.params["prey_max_moves"]): + + neighbours = self.neighbours(self.lattice, pos[0], pos[1]) + + dy = np.random.randint(neighbours.shape[0]) + dx = np.random.randint(neighbours.shape[1]) + + # If neighbouring cell is occupied, skip turn + if neighbours[dy][dx] != 0: + continue + + dest_y = dy - 1 + pos[0] + dest_x = dx - 1 + pos[1] + + # Check boundaries of the lattice + if dest_y not in range(self.size_y) or dest_x not in range( + self.size_x + ): + dest_y, dest_x = self.lattice_wrap_idx( + (dest_y, dest_x), np.shape(self.lattice) + ) + + # Move prey, clear previous location + self.lattice[dest_y][dest_x] = int(prey + 1) + self.lattice[pos[0]][pos[1]] = 0 + + # Update prey location in the list + pos[0], pos[1] = dest_y, dest_x + + neighbours = self.neighbours( + self.lattice, self.preys_loc[prey][0], self.preys_loc[prey][1] + ) + mates = neighbours[(neighbours > 0) & (neighbours != prey + 1)] + if len(mates) < 1: + continue + else: + # -1 for lattice offset + mate = int(choice(mates)) - 1 + mating_pop.append([prey, mate]) + + return mating_pop + + def place_offspring(self, offspring): + """Try to place the offsprings to the lattice. If no empty spot found within + number of max attempts, do not place. + + Parameters + ---------- + offspring : int + number of offsprings + + Returns + ------- + list + Successfully placed offspring indices. + """ + + # Keep track of offspring in a list + placed_offspring = [] + + for i in range(offspring): + + y = np.random.randint(self.size_y) + x = np.random.randint(self.size_x) + + for j in range(self.params["offspring_place_attempts"]): + if self.lattice[y][x] != 0: + continue + + else: + + if self.lattice[y][x] == 0: + # Append the offspring to the list of preys. + # len(self.preys_loc) is the index of the current last prey in the list + self.lattice[y][x] = int(len(self.preys_loc) + 1) + self.preys_loc.append([y, x]) + placed_offspring.append(i) + + return placed_offspring + + def move_predator(self): + """Find an empty position in the predator neighbourhood for the predators to move in, + move the predator and kill the weakest prey in its neighbourhood, if any. + Repeat until > predator_max_moves.""" + + predator_max_moves = int( + ( + len(self.params["population"].individuals) + - self.params["target_pop_size"] + ) + / self.params["predator_pop_size"] + ) + + # Track killed preys in list and remove them at the end of the function + to_be_killed = [] + + for predator, pos in enumerate(self.predators_loc): + + for i in range(predator_max_moves): + + neighbours = self.neighbours( + self.lattice, pos[0], pos[1], n=self.params["neighbourhood_radius"] + ) + targets = neighbours[neighbours > 0] + + # If preys found in the neighbourhood, calculate their fitness and kill the weakest + if len(targets) > 0: + fitness = [] + weakest_prey = None + for target in targets: + + obj1 = self.params["population"].fitness[target - 1][0] + obj2 = self.params["population"].fitness[target - 1][1] + + fc = ( + self.predator_pop[predator] * obj1 + + (1 - self.predator_pop[predator]) * obj2 + ) + + fitness.append((fc, target)) + fitness.sort() + weakest_prey = fitness[-1][1] - 1 + + # Kill the weakest prey and move the predator to its place + self.lattice[self.preys_loc[weakest_prey][0]][ + self.preys_loc[weakest_prey][1] + ] = -1 * (predator + 1) + + # Set the old predator location to zero + self.lattice[pos[0]][pos[1]] = 0 + + # Update predator location in the list of predators + pos[0], pos[1] = ( + self.preys_loc[weakest_prey][0], + self.preys_loc[weakest_prey][1], + ) + + # Set the killed prey as dead in the list of prey locations and end predator turn + to_be_killed.append(weakest_prey) + self.preys_loc[weakest_prey] = None + + else: + dy = np.random.randint(neighbours.shape[0]) + dx = np.random.randint(neighbours.shape[1]) + + # If neighbouring cell is occupied by another predator, skip turn + if neighbours[dy][dx] < 0: + continue + + dest_y = dy - 1 + pos[0] + dest_x = dx - 1 + pos[1] + + # Check boundaries of the lattice + if dest_y not in range(self.size_y) or dest_x not in range( + self.size_x + ): + dest_y, dest_x = self.lattice_wrap_idx( + (dest_y, dest_x), np.shape(self.lattice) + ) + + # Move predator, clear previous location + self.lattice[dest_y][dest_x] = -1 * (predator + 1) + self.lattice[pos[0]][pos[1]] = 0 + + # Update predator location in the list + pos[0], pos[1] = dest_y, dest_x + + # Remove killed prey from population + self.params["population"].delete(to_be_killed) + self.update_lattice() + + def update_lattice(self, selected=None): + """Update prey positions in the lattice. + + Parameters + ---------- + selected : list + Indices of preys to be removed from the lattice. + + """ + # Remove selected individuals from the lattice + if selected is not None: + for i in selected: + self.lattice[self.preys_loc[i][0]][self.preys_loc[i][1]] = 0 + self.preys_loc[i] = None + + # Update the list of prey locations + updated_preys = [x for x in self.preys_loc if x is not None] + self.preys_loc = updated_preys + + # Update lattice + for prey, pos in enumerate(self.preys_loc): + self.lattice[pos[0]][pos[1]] = prey + 1 + + @staticmethod + def lattice_wrap_idx(index, lattice_shape): + """Returns periodic lattice index + for a given iterable index. + + Parameters + ---------- + index : tuple + one integer for each axis + lattice_shape : tuple + the shape of the lattice to index to + """ + + if not hasattr(index, "__iter__"): + return index # handle integer slices + if len(index) != len(lattice_shape): + return index # must reference a scalar + if any(type(i) == slice for i in index): + return index # slices not supported + if len(index) == len(lattice_shape): # periodic indexing of scalars + mod_index = tuple(((i % s + s) % s for i, s in zip(index, lattice_shape))) + return mod_index + raise ValueError("Unexpected index: {}".format(index)) + + @staticmethod + def neighbours(arr, x, y, n=3): + """Given a 2D-array, returns an n*n array whose "center" element is arr[x,y] + + Parameters + ---------- + arr : ndarray + A 2D-array where to get the neighbouring cells + x : int + X coordinate for the center element + y : int + Y coordinate for the center element + n : int + Radius of the neighbourhood + + Returns + ------- + The neighbouring cells of x, y in radius n*n. Defaults to Moore neighbourhood (n=3). + """ + + arr = np.roll(np.roll(arr, shift=-x + 1, axis=0), shift=-y + 1, axis=1) + return arr[:n, :n] diff --git a/pyrvea/EAs/RVEA.py b/pyrvea/EAs/RVEA.py index e07981b..74ae8c5 100644 --- a/pyrvea/EAs/RVEA.py +++ b/pyrvea/EAs/RVEA.py @@ -35,10 +35,10 @@ def set_params( lattice_resolution: int = None, interact: bool = False, a_priori_preference: bool = False, - generations_per_iteration: int = 10, + generations_per_iteration: int = 100, iterations: int = 10, Alpha: float = 2, - plotting: bool = True, + **kwargs ): """Set up the parameters. Save in RVEA.params. Note, this should be changed to align with the current structure. @@ -61,8 +61,6 @@ def set_params( Total Number of iterations. Alpha : float The alpha parameter of APD selection. - plotting : bool - Useless really. Returns ------- @@ -92,13 +90,16 @@ def set_params( "generations": generations_per_iteration, "iterations": iterations, "Alpha": Alpha, - "ploton": plotting, "current_iteration_gen_count": 0, "current_iteration_count": 0, + "current_total_gen_count": 0, + "total_generations": generations_per_iteration * iterations, "reference_vectors": ReferenceVectors( lattice_resolution, population.problem.num_of_objectives ), + "prob_mutation": 1 / population.num_var, } + rveaparams.update(kwargs) return rveaparams def _run_interruption(self, population: "Population"): diff --git a/pyrvea/EAs/TournamentEA.py b/pyrvea/EAs/TournamentEA.py new file mode 100644 index 0000000..54b9569 --- /dev/null +++ b/pyrvea/EAs/TournamentEA.py @@ -0,0 +1,162 @@ +from pyrvea.EAs.baseEA import BaseEA +from pyrvea.Population.Population import Population +from pyrvea.Selection.tournament_select import tour_select +from random import sample +from operator import attrgetter +import numpy as np + + +class TournamentEA: + def __init__(self, population: "Population", ea_parameters): + """Run generations of evolutionary algorithm using tournament selection. + + Parameters + ---------- + population : "Population" + This variable is updated as evolution takes place + ea_parameters : dict + Takes the EA parameters. + + Returns + ------- + Population: + Returns the Population after evolution. + """ + + self.params = self.set_params(population, **ea_parameters) + + def set_params( + self, + population: "Population", + tournament_size: int = 5, + target_pop_size: int = 500, + generations_per_iteration: int = 10, + iterations: int = 10, + prob_crossover: float = 0.9, + prob_mutation: float = 0.3, + min_fitness: float = 0.001, + ): + """Set up the parameters. + + Parameters + ---------- + population : Population + Population object. + tournament_size : int + Number of participants in tournament selection. + target_pop_size : int + Desired population size. + generations_per_iteration : int + Number of generations per iteration. + iterations : int + Total number of iterations. + prob_crossover : float + Probability of crossover occurring. + prob_mutation : float + Probability of mutation occurring. + min_fitness : float + If error of the best solution < min_fitness, stop evolution. + + Returns + ------- + params : dict + Parameters for the algorithm. + + """ + + params = { + "population": population, + "tournament_size": tournament_size, + "target_pop_size": target_pop_size, + "generations": generations_per_iteration, + "iterations": iterations, + "total_generations": iterations * generations_per_iteration, + "current_iteration_gen_count": 0, + "current_total_gen_count": 0, + "current_iteration_count": 0, + "prob_crossover": prob_crossover, + "prob_mutation": prob_mutation, + "min_fitness": min_fitness, + } + return params + + def _next_iteration(self, population: "Population"): + """Run one iteration of EA. + + One iteration consists of a constant or variable number of + generations. This method leaves EA.params unchanged, except the current + iteration count and gen count. + + Parameters + ---------- + population : "Population" + Contains current population + """ + self.params["current_iteration_gen_count"] = 1 + while self.continue_iteration(): + self._next_gen(population) + self.params["current_iteration_gen_count"] += 1 + self.params["current_total_gen_count"] += 1 + self.params["current_iteration_count"] += 1 + + def _next_gen(self, population: "Population"): + """Run one generation of decomposition based EA. + + This method leaves method.params unchanged. Intended to be used by + next_iteration. + + Parameters + ---------- + population: "Population" + Population object + """ + + selected = self.select(population) + offspring = population.mate(mating_pop=selected, params=self.params) + population.delete(np.arange(len(population.individuals))) + population.add(offspring) + + def continue_iteration(self): + """Checks whether the current iteration should be continued or not.""" + return self.params["current_iteration_gen_count"] <= self.params["generations"] + + def _run_interruption(self, population: "Population"): + """Run the interruption phase of PPGA. + + Use this phase to make changes to PPGA.params or other objects. + + Parameters + ---------- + population : Population + """ + + pass + + def select(self, population) -> list: + """Select parents for recombination using tournament selection. + Chooses two parents, which are needed for crossover. + + Parameters + ---------- + population : Population + Contains the current population and problem + information. + + Returns + ------- + parents : list + List of indices of individuals to be selected. + """ + parents = [] + for i in range(int(self.params["target_pop_size"] / 2)): + parents.append( + [ + tour_select( + population.fitness, self.params["tournament_size"] + ), + tour_select( + population.fitness, self.params["tournament_size"] + ), + ] + ) + return parents diff --git a/pyrvea/EAs/baseEA.py b/pyrvea/EAs/baseEA.py index 6a2a5e8..49a2e0f 100644 --- a/pyrvea/EAs/baseEA.py +++ b/pyrvea/EAs/baseEA.py @@ -1,4 +1,5 @@ from typing import TYPE_CHECKING +import time if TYPE_CHECKING: from pyrvea.Population.Population import Population @@ -35,7 +36,7 @@ class BaseDecompositionEA(BaseEA): Evolutionary algorithms, such as RVEA or NSGA-III. """ - def __init__(self, population: "Population", EA_parameters: dict = None): + def __init__(self, population: "Population", ea_parameters): """Initialize a Base Decomposition EA. This will call methods to set up the parameters of RVEA, create @@ -53,7 +54,10 @@ def __init__(self, population: "Population", EA_parameters: dict = None): Population: Returns the Population after evolution. """ - self.params = self.set_params(population, EA_parameters) + if ea_parameters: + self.params = self.set_params(population, **ea_parameters) + else: + self.params = self.set_params(population) # print("Using BaseDecompositionEA init") self._next_iteration(population) @@ -73,6 +77,7 @@ def _next_iteration(self, population: "Population"): while self.continue_iteration(): self._next_gen(population) self.params["current_iteration_gen_count"] += 1 + self.params["current_total_gen_count"] += 1 self.params["current_iteration_count"] += 1 def _next_gen(self, population: "Population"): @@ -86,10 +91,11 @@ def _next_gen(self, population: "Population"): population: "Population" Population object """ - offspring = population.mate() + + offspring = population.mate(params=self.params) population.add(offspring) selected = self.select(population) - population.keep(selected) + population.delete(selected, preserve=True) def select(self, population) -> list: """Describe a selection mechanism. Return indices of selected diff --git a/pyrvea/EAs/slowRVEA.py b/pyrvea/EAs/slowRVEA.py index 0069574..c06d21d 100644 --- a/pyrvea/EAs/slowRVEA.py +++ b/pyrvea/EAs/slowRVEA.py @@ -1,7 +1,8 @@ from pyrvea.EAs.RVEA import RVEA from pyrvea.OtherTools.ReferenceVectors import ReferenceVectors from typing import TYPE_CHECKING -from pyrvea.Problem.testProblem import testProblem +from pyrvea.Problem.testproblem import TestProblem +from pyrvea.Population.create_individuals import create_new_individuals import numpy as np if TYPE_CHECKING: @@ -11,7 +12,7 @@ class slowRVEA(RVEA): """RVEA variant that impliments slow reference vector movement.""" - def __init__(self, population: "Population", EA_parameters: dict = None): + def __init__(self, population: "Population", ea_parameters): """Initialize a Base Decomposition EA. This will call methods to set up the parameters of RVEA, create @@ -29,21 +30,24 @@ def __init__(self, population: "Population", EA_parameters: dict = None): Population: Returns the Population after evolution. """ - self.params = self.set_params(population, **EA_parameters) - if population.individuals.shape[0] == 0: - population.create_new_individuals(pop_size=self.params["population_size"]) - # print("Using BaseDecompositionEA init") - self._next_iteration(population) + if ea_parameters: + self.params = self.set_params(population, **ea_parameters) + else: + self.params = self.set_params(population) + # if population.individuals.shape[0] == 0: + # create_new_individuals(pop_size=self.params["population_size"]) + # # print("Using BaseDecompositionEA init") + # self._next_iteration(population) def set_params( self, population: "Population", - generations_per_iteration: int = 100, + generations_per_iteration: int = 10, iterations: int = 10, Alpha: float = 2, - plotting: bool = True, ref_point: list = None, old_point: list = None, + **kwargs ): """Set up the parameters. Save in RVEA.params. Note, this should be changed to align with the current structure. @@ -73,31 +77,16 @@ def set_params( "generations": generations_per_iteration, "iterations": iterations, "Alpha": Alpha, - "ploton": plotting, "current_iteration_gen_count": 0, "current_iteration_count": 0, + "current_total_gen_count": 0, + "total_generations": iterations * generations_per_iteration, "ref_point": ref_point, } + rveaparams.update(kwargs) return rveaparams def _run_interruption(self, population: "Population"): self.params["reference_vectors"].slow_interactive_adapt( self.params["ref_point"] - ) - - def _next_gen(self, population: "Population"): - """Run one generation of decomposition based EA. - - This method leaves method.params unchanged. Intended to be used by - next_iteration. - - Parameters - ---------- - population: "Population" - Population object - """ - offspring = population.mate() - offspring = np.vstack((offspring, population.mate())) - population.add(offspring) - selected = self.select(population) - population.keep(selected) \ No newline at end of file + ) \ No newline at end of file diff --git a/pyrvea/OtherTools/ReferenceVectors.py b/pyrvea/OtherTools/ReferenceVectors.py index c4a60f5..cd300e2 100644 --- a/pyrvea/OtherTools/ReferenceVectors.py +++ b/pyrvea/OtherTools/ReferenceVectors.py @@ -233,6 +233,7 @@ def normalize(self): norm_1 = np.repeat(norm_1, self.number_of_objectives).reshape( self.number_of_vectors, self.number_of_objectives ) + norm_2[norm_2 == 0] = np.finfo(float).eps self.values = np.divide(self.values, norm_2) self.values_planar = np.divide(self.values_planar, norm_1) @@ -241,6 +242,7 @@ def neighbouring_angles(self) -> np.ndarray: cosvv = np.dot(self.values, self.values.transpose()) cosvv.sort(axis=1) cosvv = np.flip(cosvv, 1) + cosvv[cosvv > 1] = 1 acosvv = np.arccos(cosvv[:, 1]) self.neighbouring_angles_current = acosvv return acosvv diff --git a/pyrvea/OtherTools/symmetric_vectors.py b/pyrvea/OtherTools/symmetric_vectors.py index 3fbcdbc..c95843c 100644 --- a/pyrvea/OtherTools/symmetric_vectors.py +++ b/pyrvea/OtherTools/symmetric_vectors.py @@ -1,4 +1,4 @@ -from plotlyanimate import animate_init_, animate_next_ +from pyrvea.OtherTools.plotlyanimate import animate_init_, animate_next_ import numpy as np from itertools import product diff --git a/pyrvea/Population/Population.py b/pyrvea/Population/Population.py index 9faa2cf..5e9420f 100644 --- a/pyrvea/Population/Population.py +++ b/pyrvea/Population/Population.py @@ -1,21 +1,32 @@ from collections import defaultdict from collections.abc import Sequence -from random import shuffle -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING import numpy as np import pandas as pd -from pyDOE import lhs from pygmo import fast_non_dominated_sorting as nds from pygmo import hypervolume as hv from pygmo import non_dominated_front_2d as nd2 + from tqdm import tqdm, tqdm_notebook +from pyrvea.Population.create_individuals import create_new_individuals +import plotly +import plotly.graph_objs as go + from pyrvea.OtherTools.plotlyanimate import animate_init_, animate_next_ from pyrvea.OtherTools.IsNotebook import IsNotebook +from pyrvea.Recombination import ( + biogp_xover, + biogp_mutation, + evodn2_xover_mutation, + evonn_xover_mutation, + bounded_polynomial_mutation, + simulated_binary_crossover, +) if TYPE_CHECKING: - from pyrvea.Problem.baseProblem import baseProblem + from pyrvea.Problem.baseproblem import BaseProblem from pyrvea.EAs.baseEA import BaseEA @@ -24,16 +35,20 @@ class Population: def __init__( self, - problem: "baseProblem", - assign_type: str = "LHSDesign", - plotting: bool = True, + problem: "BaseProblem", + assign_type: str = "RandomDesign", + plotting: bool = False, + pop_size=None, + recombination_type=None, + crossover_type="simulated_binary_crossover", + mutation_type="bounded_polynomial_mutation", *args ): """Initialize the population. Parameters ---------- - problem : baseProblem + problem : BaseProblem An object of the class Problem assign_type : str, optional Define the method of creation of population. @@ -41,136 +56,83 @@ def __init__( randomly. If 'assign_type' is 'LHSDesign', the population is generated via Latin Hypercube Sampling. If 'assign_type' is 'custom', the population is imported from file. If assign_type - is 'empty', create blank population. (the default is "RandomAssign") + is 'empty', create blank population. + 'EvoNN' and 'EvoDN2' will create neural networks or deep neural networks, respectively, + for population . plotting : bool, optional (the default is True, which creates the plots) + pop_size : int + Population size + recombination_type, crossover_type, mutation_type : str + Recombination functions. If recombination_type is specified, crossover and mutation + will be handled by the same function. If None, they are done separately. """ - num_var = problem.num_of_variables + self.assign_type = assign_type + self.num_var = problem.num_of_variables self.lower_limits = np.asarray(problem.lower_limits) self.upper_limits = np.asarray(problem.upper_limits) self.hyp = 0 self.non_dom = 0 + self.pop_size = pop_size + self.recombination_funcs = { + "biogp_xover": biogp_xover, + "biogp_mut": biogp_mutation, + "evodn2_xover_mutation": evodn2_xover_mutation, + "evonn_xover_mutation": evonn_xover_mutation, + "bounded_polynomial_mutation": bounded_polynomial_mutation, + "simulated_binary_crossover": simulated_binary_crossover, + } + self.crossover_type = crossover_type + self.mutation_type = mutation_type + self.recombination = self.recombination_funcs.get(recombination_type, None) + if recombination_type is None: + self.crossover = self.recombination_funcs.get(crossover_type, None) + self.mutation = self.recombination_funcs.get(mutation_type, None) self.problem = problem - self.filename = problem.name + "_" + str(problem.num_of_objectives) + self.filename = ( + problem.name + "_" + str(problem.num_of_objectives) + ) # Used for plotting self.plotting = plotting - # These attributes contain the solutions. - self.individuals = np.empty((0, num_var), float) + self.individuals = [] self.objectives = np.empty((0, self.problem.num_of_objectives), float) - self.fitness = np.empty((0, self.problem.num_of_objectives), float) + if problem.minimize is not None: + self.fitness = self.objectives[:, self.problem.minimize] + self.ideal_fitness = np.full((1, self.fitness.shape[1]), np.inf) + self.worst_fitness = -1 * self.ideal_fitness + else: + self.fitness = np.empty((0, self.problem.num_of_objectives), float) + self.ideal_fitness = np.full((1, self.problem.num_of_objectives), np.inf) + self.worst_fitness = -1 * self.ideal_fitness self.constraint_violation = np.empty( (0, self.problem.num_of_constraints), float ) self.archive = pd.DataFrame( columns=["generation", "decision_variables", "objective_values"] ) - self.ideal_fitness = np.full((1, self.problem.num_of_objectives), np.inf) - self.worst_fitness = -1 * self.ideal_fitness - if not assign_type == "empty": - self.create_new_individuals(assign_type) - - def create_new_individuals( - self, design: str = "LHSDesign", pop_size: int = None, decision_variables=None - ): - """Create, evaluate and add new individuals to the population. Initiate Plots. - - The individuals can be created randomly, by LHS design, or can be passed by the - user. - Parameters - ---------- - design : str, optional - Describe the method of creation of new individuals. - "RandomDesign" creates individuals randomly. - "LHSDesign" creates individuals using Latin hypercube sampling. - pop_size : int, optional - Number of individuals in the population. If none, some default population - size based on number of objectives is chosen. - decision_variables : numpy array or list, optional - Pass decision variables to be added to the population. - """ - if decision_variables is not None: - pass - if pop_size is None: - pop_size_options = [50, 105, 120, 126, 132, 112, 156, 90, 275] - pop_size = pop_size_options[self.problem.num_of_objectives - 2] - num_var = self.individuals.shape[1] - if design == "RandomDesign": - individuals = np.random.random((pop_size, num_var)) - # Scaling - individuals = ( - individuals * (self.upper_limits - self.lower_limits) - + self.lower_limits - ) - elif design == "LHSDesign": - individuals = lhs(num_var, samples=pop_size) - # Scaling - individuals = ( - individuals * (self.upper_limits - self.lower_limits) - + self.lower_limits + if not assign_type == "empty": + individuals = create_new_individuals( + assign_type, problem, pop_size=self.pop_size ) - else: - print("Design not yet supported.") - self.add(individuals) + self.add(individuals) + if self.plotting: self.figure = [] self.plot_init_() - def eval_fitness(self): - """ - Calculate fitness based on objective values. Fitness = obj if minimized. - """ - fitness = self.objectives * self.problem.objs - return fitness - - def add(self, new_pop: np.ndarray): + def add(self, new_pop: list): """Evaluate and add individuals to the population. Update ideal and nadir point. Parameters ---------- - new_pop: np.ndarray + new_pop: list Decision variable values for new population. """ - if new_pop.ndim == 1: - self.append_individual(new_pop) - elif new_pop.ndim == 2: - for ind in new_pop: - self.append_individual(ind) - else: - print("Error while adding new individuals. Check dimensions.") - # print(self.ideal_fitness) - self.update_ideal_and_nadir() - - def keep(self, indices: list): - """Remove individuals from population which are not in "indices". + for i in range(len(new_pop)): + self.append_individual(new_pop[i]) - Parameters - ---------- - indices: list - Indices of individuals to keep - """ - - new_pop = self.individuals[indices, :] - new_obj = self.objectives[indices, :] - new_fitness = self.fitness[indices, :] - new_CV = self.constraint_violation[indices, :] - self.individuals = new_pop - self.objectives = new_obj - length_of_archive = len(self.archive) - if length_of_archive == 0: - gen_count = 0 - else: - gen_count = self.archive["generation"].iloc[-1] + 1 - new_entries = pd.DataFrame( - { - "generation": [gen_count] * len(new_obj), - "decision_variables": new_pop.tolist(), - "objective_values": new_obj.tolist(), - } - ) - self.archive = self.archive.append(new_entries, ignore_index=True) - self.fitness = new_fitness - self.constraint_violation = new_CV + self.update_ideal_and_nadir() def append_individual(self, ind: np.ndarray): """Evaluate and add individual to the population. @@ -179,7 +141,8 @@ def append_individual(self, ind: np.ndarray): ---------- ind: np.ndarray """ - self.individuals = np.vstack((self.individuals, ind)) + + self.individuals.append(ind) obj, CV, fitness = self.evaluate_individual(ind) self.objectives = np.vstack((self.objectives, obj)) self.constraint_violation = np.vstack((self.constraint_violation, CV)) @@ -196,13 +159,82 @@ def evaluate_individual(self, ind: np.ndarray): """ obj = self.problem.objectives(ind) CV = np.empty((0, self.problem.num_of_constraints), float) - fitness = obj + fitness = self.eval_fitness(obj) + if self.problem.num_of_constraints: CV = self.problem.constraints(ind, obj) - fitness = self.eval_fitness(ind, obj, self.problem) - return (obj, CV, fitness) + fitness = self.eval_fitness(obj) + + return obj, CV, fitness + + def eval_fitness(self, obj): + """ + Calculate fitness based on objective values. Fitness = obj if minimized. + """ + + # fitness = self.objectives * self.problem.objs + if self.problem.minimize is None: + self.problem.minimize = [True] * self.problem.num_of_objectives + else: + assert len(self.problem.minimize) == self.problem.num_of_objectives - def evolve(self, EA: "BaseEA" = None, EA_parameters: dict = None) -> "Population": + fitness = np.asarray(obj)[np.asarray(self.problem.minimize)] + + return fitness + + def update_fitness(self): + """Include or exclude objectives from fitness calculation. + Problem.minimize should be a list of booleans of same length as the number of objectives. + """ + self.fitness = self.objectives[:, self.problem.minimize] + self.ideal_fitness = np.full((1, self.fitness.shape[1]), np.inf) + self.worst_fitness = -1 * self.ideal_fitness + self.update_ideal_and_nadir() + + def delete(self, indices, preserve=False): + """Remove from population individuals which are in indices if preserve=False, otherwise + preserve them and remove all others. + + Parameters + ---------- + indices: array_like + Indices of individuals to keep or delete. + preserve: bool + Whether to delete individuals at indices from current population, or preserve them and delete others. + """ + + mask = np.ones(len(self.individuals), dtype=bool) + mask[indices] = False + + new_pop = np.array(self.individuals)[mask] + deleted_pop = np.array(self.individuals)[~mask] + + new_obj = self.objectives[mask] + deleted_obj = self.objectives[~mask] + + new_fitness = self.fitness[mask] + deleted_fitness = self.fitness[~mask] + + if len(self.constraint_violation) > 0: + new_cv = self.constraint_violation[mask] + deleted_cv = self.constraint_violation[~mask] + else: + deleted_cv = self.constraint_violation + new_cv = self.constraint_violation + + if not preserve: + self.individuals = list(new_pop) + self.objectives = new_obj + self.fitness = new_fitness + self.constraint_violation = new_cv + + else: + self.individuals = list(deleted_pop) + self.objectives = deleted_obj + self.fitness = deleted_fitness + self.constraint_violation = deleted_cv + + def evolve(self, EA: "BaseEA" = None, ea_parameters: dict = None): """Evolve the population with interruptions. Evolves the population based on the EA sent by the user. @@ -211,91 +243,54 @@ def evolve(self, EA: "BaseEA" = None, EA_parameters: dict = None) -> "Population ---------- EA: "BaseEA" Should be a derivative of BaseEA (Default value = None) - EA_parameters: dict + ea_parameters: dict Contains the parameters needed by EA (Default value = None) """ ################################## # To determine whether running in console or in notebook. Used for TQDM. # TQDM will be removed in future generations as number of iterations can vary + if IsNotebook(): progressbar = tqdm_notebook else: progressbar = tqdm #################################### # A basic evolution cycle. Will be updated to optimize() in future versions. - ea = EA(self, EA_parameters) + ea = EA(self, ea_parameters) iterations = ea.params["iterations"] + if self.plotting: self.plot_objectives() # Figure was created in init - for i in progressbar(range(1, iterations), desc="Iteration"): + for i in progressbar(range(iterations), desc="Iteration"): ea._run_interruption(self) ea._next_iteration(self) if self.plotting: self.plot_objectives() - def mate(self): + def mate(self, mating_pop=None, params=None): """Conduct crossover and mutation over the population. - Conduct simulated binary crossover and bounded polunomial mutation. """ - pop = self.individuals - pop_size, num_var = pop.shape - shuffled_ids = list(range(pop_size)) - shuffle(shuffled_ids) - mating_pop = pop[shuffled_ids] - if pop_size % 2 == 1: - # Maybe it should be pop_size-1? - mating_pop = np.vstack((mating_pop, mating_pop[0])) - pop_size = pop_size + 1 - # The rest closely follows the matlab code. - ProC = 1 - ProM = 1 / num_var - DisC = 30 - DisM = 20 - offspring = np.zeros_like(mating_pop) # empty_like() more efficient? - for i in range(0, pop_size, 2): - beta = np.zeros(num_var) - miu = np.random.rand(num_var) - beta[miu <= 0.5] = (2 * miu[miu <= 0.5]) ** (1 / (DisC + 1)) - beta[miu > 0.5] = (2 - 2 * miu[miu > 0.5]) ** (-1 / (DisC + 1)) - beta = beta * ((-1) ** np.random.randint(0, high=2, size=num_var)) - beta[np.random.rand(num_var) > ProC] = 1 # It was in matlab code - avg = (mating_pop[i] + mating_pop[i + 1]) / 2 - diff = (mating_pop[i] - mating_pop[i + 1]) / 2 - offspring[i] = avg + beta * diff - offspring[i + 1] = avg - beta * diff - min_val = np.ones_like(offspring) * self.lower_limits - max_val = np.ones_like(offspring) * self.upper_limits - k = np.random.random(offspring.shape) - miu = np.random.random(offspring.shape) - temp = np.logical_and((k <= ProM), (miu < 0.5)) - offspring_scaled = (offspring - min_val) / (max_val - min_val) - offspring[temp] = offspring[temp] + ( - (max_val[temp] - min_val[temp]) - * ( - ( - 2 * miu[temp] - + (1 - 2 * miu[temp]) * (1 - offspring_scaled[temp]) ** (DisM + 1) - ) - ** (1 / (DisM + 1)) - - 1 + + if self.recombination is not None: + offspring = self.recombination.mate( + mating_pop, + self.individuals, + params, + crossover_type=self.crossover_type, + mutation_type=self.mutation_type, ) - ) - temp = np.logical_and((k <= ProM), (miu >= 0.5)) - offspring[temp] = offspring[temp] + ( - (max_val[temp] - min_val[temp]) - * ( - 1 - - ( - 2 * (1 - miu[temp]) - + 2 * (miu[temp] - 0.5) * offspring_scaled[temp] ** (DisM + 1) - ) - ** (1 / (DisM + 1)) + else: + offspring = self.crossover.mate(mating_pop, self.individuals, params) + self.mutation.mutate( + offspring, + self.individuals, + params, + self.lower_limits, + self.upper_limits, ) - ) - offspring[offspring > max_val] = max_val[offspring > max_val] - offspring[offspring < min_val] = min_val[offspring < min_val] + return offspring def plot_init_(self): @@ -317,6 +312,55 @@ def plot_objectives(self, iteration: int = None): obj, self.figure, self.filename + ".html", iteration ) + def plot_pareto(self, name, show_all=False): + """Plot the pareto front. + + Parameters + ---------- + name : str + Name to append to the plot filename. + show_all : bool + Show all solutions, including those not on the pareto front. + + """ + if name is None: + name = self.problem.name + + ndf = self.non_dominated() + #pareto = self.objectives[ndf][self.objectives[ndf].min(axis=1) >= 0, :] + pareto = self.objectives[ndf] + pareto_pop = np.asarray(self.individuals)[ndf].tolist() + + for idx, x in enumerate(pareto_pop): + + for i, y in enumerate(x): + x[i] = "x" + str(i + 1) + ": " + str(y) + "
" + x.insert(0, "Model " + str(idx)) + + trace0 = go.Scatter( + x=pareto[:, 0], + y=pareto[:, 1], + text=pareto_pop, + hoverinfo="text", + mode="markers+lines", + ) + + if show_all: + trace1 = go.Scatter( + x=self.objectives[:, 0], y=self.objectives[:, 1], mode="markers" + ) + + data = [trace0, trace1] + else: + data = [trace0] + + layout = go.Layout(xaxis=dict(title="f1"), yaxis=dict(title="f2")) + plotly.offline.plot( + {"data": data, "layout": layout}, + filename=name + "pareto" + ".html", + auto_open=True, + ) + def hypervolume(self, ref_point): """Calculate hypervolume. Uses package pygmo. Add checks to prevent errors. diff --git a/pyrvea/Population/create_individuals.py b/pyrvea/Population/create_individuals.py new file mode 100644 index 0000000..af92a5f --- /dev/null +++ b/pyrvea/Population/create_individuals.py @@ -0,0 +1,139 @@ +import numpy as np +import random +from math import ceil +from pyDOE import lhs + + +def create_new_individuals(design, problem, pop_size=None): + """Create new individuals to the population. + + The individuals can be created randomly, by LHS design, or can be passed by the + user. + + Design does not apply in case of EvoNN and EvoDN2 problem, where neural networks are created + as individuals. + + Parameters + ---------- + design : str, optional + Describe the method of creation of new individuals. + "RandomDesign" creates individuals randomly. + "LHSDesign" creates individuals using Latin hypercube sampling. + "EvoNN" creates Artificial Neural Networks as individuals. + "EvoDN2" creates Deep Neural Networks. + problem : baseProblem + An object of the class Problem + pop_size : int, optional + Number of individuals in the population. If none, some default population + size based on number of objectives is chosen. + + Returns + ------- + individuals : list + A list of individuals. + + """ + + if pop_size is None: + pop_size_options = [50, 105, 120, 126, 132, 112, 156, 90, 275] + pop_size = pop_size_options[problem.num_of_objectives - 2] + + if design == "RandomDesign": + lower_limits = np.asarray(problem.lower_limits) + upper_limits = np.asarray(problem.upper_limits) + individuals = np.random.random((pop_size, problem.num_of_variables)) + # Scaling + individuals = ( + individuals * (upper_limits - lower_limits) + + lower_limits + ) + + return individuals + + elif design == "LHSDesign": + lower_limits = np.asarray(problem.lower_limits) + upper_limits = np.asarray(problem.upper_limits) + individuals = lhs(problem.num_of_variables, samples=pop_size) + # Scaling + individuals = ( + individuals * (upper_limits - lower_limits) + + lower_limits + ) + + return individuals + + elif design == "EvoNN": + + """Create a population of neural networks for the EvoNN algorithm. + + Individuals are 2d arrays representing the weight matrices of the NNs. + One extra row is added for bias. + + """ + + w_low = problem.params["w_low"] + w_high = problem.params["w_high"] + in_nodes = problem.num_of_variables + num_nodes = problem.params["num_nodes"] + prob_omit = problem.params["prob_omit"] + + individuals = np.random.uniform( + w_low, + w_high, + size=(pop_size, in_nodes, num_nodes), + ) + + # Randomly set some weights to zero + zeros = np.random.choice( + np.arange(individuals.size), + ceil(individuals.size * prob_omit), + ) + individuals.ravel()[zeros] = 0 + + # Set bias + individuals = np.insert(individuals, 0, 1, axis=1) + + return individuals + + elif design == "EvoDN2": + """Create a population of deep neural networks (DNNs) for the EvoDN2 algorithm. + + Each individual is a list of subnets, and each subnet contains a random amount of layers and + nodes per layer. The subnets are evolved via evolutionary algorithms, and they converge + on the final linear layer of the DNN. + + """ + + individuals = [] + for i in range(problem.params["pop_size"]): + nets = [] + for j in range(problem.params["num_subnets"]): + + layers = [] + num_layers = np.random.randint(1, problem.params["max_layers"]) + in_nodes = len(problem.subsets[j]) + + for k in range(num_layers): + out_nodes = random.randint(2, problem.params["max_nodes"]) + net = np.random.uniform( + problem.params["w_low"], problem.params["w_high"], size=(in_nodes, out_nodes) + ) + # Randomly set some weights to zero + zeros = np.random.choice( + np.arange(net.size), ceil(net.size * problem.params["prob_omit"]) + ) + net.ravel()[zeros] = 0 + + # Add bias + net = np.insert(net, 0, 1, axis=0) + in_nodes = out_nodes + layers.append(net) + + nets.append(layers) + + individuals.append(nets) + + return individuals + + elif design == "BioGP": + return problem.create_individuals() diff --git a/pyrvea/Problem/baseProblem.py b/pyrvea/Problem/baseproblem.py similarity index 87% rename from pyrvea/Problem/baseProblem.py rename to pyrvea/Problem/baseproblem.py index 3f42cd6..6388ce0 100644 --- a/pyrvea/Problem/baseProblem.py +++ b/pyrvea/Problem/baseproblem.py @@ -1,4 +1,4 @@ -class baseProblem: +class BaseProblem: """Base class for the problems.""" def __init__( @@ -35,6 +35,7 @@ def __init__( self.obj_func = [] self.upper_limits = upper_limits self.lower_limits = lower_limits + self.minimize = None def objectives(self, decision_variables): """Accept a sample. Return Objective values. @@ -45,15 +46,16 @@ def objectives(self, decision_variables): """ pass - def constraints(self, decision_variables): + def constraints(self, decision_variables, objective_variables): """Accept a sample and/or corresponding objective values. Parameters ---------- decision_variables + objective_variables """ pass - def update(): + def update(self): """Update the problem based on new information.""" pass diff --git a/pyrvea/Problem/biogp_problem.py b/pyrvea/Problem/biogp_problem.py new file mode 100644 index 0000000..2c876fe --- /dev/null +++ b/pyrvea/Problem/biogp_problem.py @@ -0,0 +1,842 @@ +from random import random, randint, choice, seed +from graphviz import Digraph, Source +import numpy as np +import pandas as pd +from math import ceil +from pyrvea.Problem.baseproblem import BaseProblem +from pyrvea.EAs.PPGA import PPGA +from pyrvea.EAs.TournamentEA import TournamentEA +from pyrvea.Population.Population import Population +import plotly +import plotly.graph_objs as go + + +class BioGP(BaseProblem): + """Creates syntax tree models to use for genetic programming through bi-objective genetic algorithms. + + The BioGP technique initially minimizes training error through a single objective optimization procedure and then a + trade-off between complexity and accuracy is worked out through a genetic algorithm based bi-objective + optimization strategy. + + The benefit of the BioGP approach is that an expert user or a decision maker (DM) can + flexibly select the mathematical operations involved to construct a meta-model of desired complexity or + accuracy. It is also designed to combat bloat – a perennial problem in genetic programming along with + over fitting and under fitting problems. + + Notes + ----- + The algorithm has been created earlier in MATLAB, and this Python implementation has been using + that code as a basis. + + Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + + Parameters + ---------- + name : str + Name of the problem. + X_train : np.ndarray + Training data input. + y_train : np.ndarray + Training data target values. + num_of_objectives : int + The number of objectives. + params : dict + Parameters for model training. + num_samples : int + The number of data points, or samples. + function_set : array_like + The function set to use when creating the trees. + terminal_set : array_like + The terminals (variables and constants) to use when creating the trees. + + References + ---------- + [1] Giri, B. K., Hakanen, J., Miettinen, K., & Chakraborti, N. (2013). Genetic programming through bi-objective + genetic algorithms with a study of a simulated moving bed process involving multiple objectives. + Applied Soft Computing, 13(5), 2613-2623. + """ + + def __init__( + self, + name=None, + X_train=None, + y_train=None, + num_of_objectives=2, + params=None, + num_samples=None, + function_set=None, + terminal_set=None, + ): + super().__init__() + + self.name = name + self.X_train = X_train + self.y_train = y_train + self.num_of_objectives = num_of_objectives + self.params = params + self.num_samples = num_samples + # These functions should be moved to their own separate package maybe + self.function_map = { + "add": self.add, + "sub": self.sub, + "mul": self.mul, + "div": self.div, + "sqrt": self.sqrt, + "log": self.log, + "sin": self.sin, + "cos": self.cos, + "tan": self.tan, + "neg": self.neg, + } + self.terminal_set = terminal_set + self.function_set = function_set + + self.individuals = [] + + def create_individuals(self): + + if self.params["init_method"] == "ramped_half_and_half": + for md in range( + ceil(self.params["max_depth"] / 2), self.params["max_depth"] + 1 + ): + for i in range( + int(self.params["pop_size"] / (self.params["max_depth"] + 1)) + ): + + ind = LinearNode(value="linear", params=self.params) + ind.grow_tree(max_depth=md, method="grow", ind=ind) + self.individuals.append(ind) + + for i in range( + int(self.params["pop_size"] / (self.params["max_depth"] + 1)) + ): + + ind = LinearNode(value="linear", params=self.params) + ind.grow_tree(max_depth=md, method="full", ind=ind) + self.individuals.append(ind) + + elif self.params["init_method"] == "full": + for i in range(self.params["pop_size"]): + ind = LinearNode(value="linear", params=self.params) + ind.grow_tree(method="full", ind=ind) + self.individuals.append(ind) + + elif self.params["init_method"] == "grow": + for i in range(self.params["pop_size"]): + ind = LinearNode(value="linear", params=self.params) + ind.grow_tree(method="grow", ind=ind) + self.individuals.append(ind) + + return self.individuals + + def objectives(self, decision_variables): + + return decision_variables.calculate_linear(self.X_train, self.y_train) + + def select(self, pop, non_dom_front, selection="min_error"): + """ Select target model from the population. + + Parameters + ---------- + pop : obj + The population object. + non_dom_front : list + Indices of the models on the non-dominated front. + selection : str + The criterion to use for selecting the model. + Possible values: 'min_error', 'akaike_corrected', 'manual' + + Returns + ------- + The selected model + """ + model = None + fitness = None + if selection == "min_error": + # Return the model with the lowest error + + lowest_error = np.argmin(pop.objectives[:, 0]) + model = pop.individuals[lowest_error] + fitness = pop.fitness[lowest_error] + + return model, fitness + + @staticmethod + def add(x, y): + return np.add(x, y) + + @staticmethod + def sub(x, y): + return np.subtract(x, y) + + @staticmethod + def mul(x, y): + return np.multiply(x, y) + + @staticmethod + def div(x, y): + y[y == 0] = 1.0 + return np.divide(x, y) + + @staticmethod + def sqrt(x): + return np.sqrt(np.abs(x)) + + @staticmethod + def log(x): + return np.where(np.abs(x) > 0.001, np.log(np.abs(x)), 0.0) + + @staticmethod + def sin(x): + return np.sin(x) + + @staticmethod + def cos(x): + return np.cos(x) + + @staticmethod + def tan(x): + return np.tan(x) + + @staticmethod + def neg(x): + return np.negative(x) + + +class BioGPModel(BioGP): + """The class for the BioGP surrogate model. + + Parameters + ---------- + model_parameters : dict + Parameters passed for the model. + ea_parameters : dict + Parameters passed for the genetic algorithm. + + Attributes + ---------- + name : str + Name of the model. + linear_node : LinearNode + The parent node of the tree containing the linear values. + fitness : list + Fitness of the trained model. + minimize : list (bool) + List of which objectives to minimize. + svr : np.ndarray + Single variable response of the model. + log : file + If logging set to True in params, external log file is stored here. + + """ + def __init__(self, model_parameters=None, ea_parameters=None): + super().__init__() + self.name = "BioGP_Model" + self.linear_node = None + self.fitness = None + self.minimize = None + self.svr = None + self.log = None + self.ea_params = ea_parameters + if model_parameters: + self.set_params(**model_parameters) + else: + self.set_params() + + def set_params( + self, + name="BioGP_Model", + training_algorithm=PPGA, + pop_size=500, + max_depth=5, + max_subtrees=4, + prob_terminal=0.5, + complexity_scalar=0.5, + error_lim=0.001, + init_method="ramped_half_and_half", + selection="min_error", + loss_func="root_mean_square", + recombination_type=None, + crossover_type="biogp_xover", + mutation_type="biogp_mut", + single_obj_generations=10, + logging=False, + plotting=False, + function_set=("add", "sub", "mul", "div"), + terminal_set=None, + ): + + """ Set parameters for the BioGP model. + + Parameters + ---------- + name : str + Name of the problem. + training_algorithm : EA + Which evolutionary algorithm to use for training the models. + pop_size : int + Population size. + max_depth : int + Maximum depth of the tree. + max_subtrees : int + Maximum number of subtrees the tree can grow. + prob_terminal : float + The probability of making the node terminal when growing the tree. + complexity_scalar : float + Complexity of the model is calculated as a weighted aggregate of the maximum depth of the GP tree + and the total number of corresponding function nodes. Larger value gives more weight to the depth, + lower more weight to the number of function nodes. + error_lim : float + Used to control bloat. If the error reduction ratio of a subtree is less than this value, + then that root is terminated and a new root is grown under the linear node (i.e., parent node). + init_method : str + Method to use for creating the initial population. Can be either 'grow', 'full', or + 'ramped_half_and_half' (default). + + grow: nodes are chosen at random from both functions and terminals, allowing for smaller trees + than max_depth. + full: nodes are chosen from the function set until the max depth is reached, and then terminals are chosen. + ramped half and half: trees are grown with a 50/50 mixture of 'grow' and 'full'. + + loss_func : str + The loss function to use. + selection : str + The selection method to use. + recombination_type, crossover_type, mutation_type : str or None + Recombination functions. If recombination_type is specified, crossover and mutation + will be handled by the same function. If None, they are done separately. + single_obj_generations : int + How many generations to run minimizing only the training error. + logging : bool + True to create a logfile, False otherwise. + plotting : bool + True to create a plot, False otherwise. + function_set : tuple + The function set to use when creating the trees. + terminal_set : list + The terminals (variables and constants) to use when creating the trees. + + """ + + params = { + "name": name, + "training_algorithm": training_algorithm, + "pop_size": pop_size, + "max_depth": max_depth, + "max_subtrees": max_subtrees, + "prob_terminal": prob_terminal, + "complexity_scalar": complexity_scalar, + "error_lim": error_lim, + "init_method": init_method, + "loss_func": loss_func, + "selection": selection, + "recombination_type": recombination_type, + "crossover_type": crossover_type, + "mutation_type": mutation_type, + "single_obj_generations": single_obj_generations, + "logging": logging, + "plotting": plotting, + "function_set": function_set, + "terminal_set": terminal_set, + } + + self.name = name + self.params = params + + def fit(self, training_data, target_values): + """Fit data in BioGP model. + + Parameters + ---------- + training_data : pd.DataFrame, shape = (numbers of samples, number of variables) + Training data. + target_values : pd.DataFrame + Target values. + + Returns + ------- + self : returns an instance of self. + + """ + + self.X_train = training_data + self.y_train = target_values + self.num_samples = target_values.shape[0] + self.num_of_variables = training_data.shape[1] + terminal_set = self.X_train.columns.tolist() + if self.params["terminal_set"]: + self.params["terminal_set"].extend(terminal_set) + function_set = [] + for function in self.params["function_set"]: + function_set.append(self.function_map[function]) + self.params["function_set"] = function_set + + self.train() + + self.single_variable_response(ploton=self.params["plotting"]) + + if self.params["logging"]: + self.create_logfile() + + return self + + def train(self): + """Trains the networks and selects the best model from the non dominated front. + + """ + + # Minimize only error for first n generations before switching to bi-objective + ea_params = { + "generations_per_iteration": 1, + "iterations": self.params["single_obj_generations"], + } + self.minimize = [True, False] + + print( + "Minimizing error for " + + str(self.params["single_obj_generations"]) + + " generations..." + ) + + pop = Population( + self, + assign_type="BioGP", + pop_size=self.params["pop_size"], + plotting=self.params["plotting"], + recombination_type=self.params["recombination_type"], + crossover_type=self.params["crossover_type"], + mutation_type=self.params["mutation_type"], + ) + + pop.evolve(EA=TournamentEA, ea_parameters=ea_params) + + # Switch to bi-objective (error, complexity) + self.minimize = [True, True] + pop.update_fitness() + + print("Switching to bi-objective mode") + + pop.evolve( + EA=self.params["training_algorithm"], ea_parameters=self.ea_params + ) + + non_dom_front = pop.non_dominated() + self.linear_node, self.fitness = self.select( + pop, non_dom_front, self.params["selection"] + ) + + def predict(self, decision_variables): + """Predict using the BioGP model. + + Parameters + ---------- + decision_variables : pd.DataFrame + The decision variables used for prediction. + + Returns + ------- + y : np.ndarray + The prediction of the model. + + """ + + sub_trees = [] + # Stack outputs of subtrees to form weight matrix + for root in self.linear_node.roots: + sub_tree = root.predict(decision_variables) + if sub_tree.size == 1: + sub_tree = sub_tree.reshape(1) + sub_trees.append(sub_tree) + + sub_trees = np.hstack(sub_trees) + axis = None + if sub_trees.ndim > 1: + axis = 1 + sub_trees = np.insert(sub_trees, 0, 1, axis=axis) + + y = np.dot(sub_trees, self.linear_node.linear) + + if isinstance(y, float): + y = np.asarray([y]) + + return y + + def plot(self, prediction, target, name=None): + """Creates and shows a plot for the model's prediction. + + Parameters + ---------- + prediction : np.ndarray + The prediction of the model. + target : pd.DataFrame + The target values. + name : str + Filename to save the plot as. + """ + target = np.asarray(target) + if name is None: + name = self.name + + trace0 = go.Scatter(x=prediction, y=target, mode="markers") + trace1 = go.Scatter(x=target, y=target) + data = [trace0, trace1] + plotly.offline.plot( + data, + filename="Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_depth" + + str(self.params["max_depth"]) + + "_subtrees" + + str(self.params["max_subtrees"]) + + ".html", + auto_open=True, + ) + + def create_logfile(self, name=None): + """Create a log file containing the parameters for training the model and the EA. + + Parameters + ---------- + name : str + Filename to save the log as. + + Returns + ------- + log_file : file + An external log file. + """ + + if name is None: + name = self.name + + # Save params to log file + log_file = open( + "Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_depth" + + str(self.params["max_depth"]) + + "_subtrees" + + str(self.params["max_subtrees"]) + + ".log", + "a", + ) + + for i in self.params: + print("", i, ":", self.params[i], file=log_file) + + if self.fitness is not None: + print("fitness: " + str(self.fitness), file=log_file) + + if self.svr is not None: + print("single variable response: " + str(self.svr), file=log_file) + + return log_file + + def single_variable_response(self, ploton=False): + """Get the model's response to a single variable. + + Parameters + ---------- + ploton : bool + Create and show plot on/off. + """ + + trend = np.loadtxt("trend") + avg = np.ones((1, self.num_of_variables)) * (np.finfo(float).eps + 1) / 2 + svr = np.empty((0, 2)) + variables = np.ones((len(trend), 1)) * avg + dataset = pd.DataFrame.from_records(variables) + dataset.columns = self.X_train.columns + + for i in range(self.num_of_variables): + + dataset.iloc[:, i] = trend + + out = self.predict(dataset) + + if min(out) == max(out): + out = 0.5 * np.ones(out.size) + else: + out = (out - min(out)) / (max(out) - min(out)) + + if ploton: + trace0 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=variables[:, i], name="input" + ) + trace1 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=out, name="output" + ) + data = [trace0, trace1] + plotly.offline.plot( + data, filename="x" + str(i + 1) + "_response.html", auto_open=True + ) + + p = np.diff(out) + q = np.diff(trend) + r = np.multiply(p, q) + r_max = max(r) + r_min = min(r) + s = None + if r_max <= 0 and r_min <= 0: + s = "inverse" + elif r_max >= 0 and r_min >= 0: + s = "direct" + elif r_max == 0 and r_min == 0: + s = "nil" + elif r_min < 0 < r_max: + s = "mixed" + + svr = np.vstack((svr, ["x" + str(i + 1), s])) + self.svr = svr + + +class Node: + """A node object representing a function or terminal node in the tree. + + Parameters + ---------- + value : function, str or float + A function node has as its value a function. Terminal nodes contain variables which are either float or str. + depth : int + The depth the node is at. + params : None or dict + The parameters of the model. + function_set : array_like + The function set to use when creating the trees. + terminal_set : array_like + The terminals (variables and constants) to use when creating the trees. + + """ + + def __init__( + self, value=None, depth=None, params=None, function_set=None, terminal_set=None + ): + self.value = value + self.depth = depth + self.params = params + self.function_set = function_set + self.terminal_set = terminal_set + self.nodes = [] + self.nodes_at_depth = None + self.total_depth = None + self.roots = [] + + def predict(self, decision_variables=None): + + if callable(self.value): + values = [root.predict(decision_variables) for root in self.roots] + if self.depth == 0: + self.value = sum(values) + return self.value + else: + return self.value(*values) + + else: + if isinstance(decision_variables, np.ndarray) and isinstance( + self.value, str + ): + return decision_variables[ + :, int("".join(filter(str.isdigit, self.value))) - 1 + ] + if isinstance(self.value, str): + return np.asarray(decision_variables[self.value]).reshape(-1, 1) + else: + return np.full((decision_variables.shape[0], 1), self.value) + + def node_label(self): # return string label + if callable(self.value): + return self.value.__name__ + else: + return str(self.value) + + def draw(self, dot, count): # dot & count are lists in order to pass "by reference" + node_name = str(count[0]) + dot[0].node(node_name, self.node_label()) + + for node in self.roots: + count[0] += 1 + dot[0].edge(node_name, str(count[0])) + node.draw(dot, count) + + def draw_tree(self, name="tree", footer=""): + dot = [Digraph()] + dot[0].attr(kw="graph", label=footer) + count = [0] + self.draw(dot, count) + Source(dot[0], filename=name + ".gv", format="png").render() + + def get_sub_nodes(self): + """Get all nodes belonging to the subtree under the current node. + + Returns + ------- + nodes : list + A list of nodes in the subtree. + + """ + nodes = [] + nodes_at_depth = {} + stack = [self] + while stack: + cur_node = stack[0] + depth = cur_node.depth + if cur_node.depth not in nodes_at_depth: + nodes_at_depth[cur_node.depth] = [] + nodes_at_depth[cur_node.depth].append(cur_node) + stack = stack[1:] + nodes.append(cur_node) + if len(cur_node.roots) > 0: + depth += 1 + for child in cur_node.roots: + child.depth = depth + stack.append(child) + + self.nodes_at_depth = nodes_at_depth + self.total_depth = max(key for key in self.nodes_at_depth.keys()) + + return nodes + + def grow_tree(self, max_depth=None, method="grow", depth=0, ind=None): + """Create a random tree recursively using either grow or full method. + + Parameters + ---------- + max_depth : int + The maximum depth of the tree. + method : str + Methods: 'grow', 'full'. + For the 'grow' method, nodes are chosen at random from both functions and terminals. + The 'full' method chooses nodes from the function set until the max depth is reached, + and then terminals are chosen. + depth : int + Current depth. + ind : :obj: + The starting node from which to begin growing trees. + + """ + node = None + if max_depth is None: + max_depth = self.params["max_depth"] + if depth == 0: + if ind is None: + ind = LinearNode(value="linear") + num_subtrees = self.params["max_subtrees"] + for i in range(len(ind.roots), num_subtrees): + node = self.grow_tree(max_depth, method, depth=depth + 1) + ind.roots.append(node) + + # Make terminal node + elif ( + depth >= max_depth + or method == "grow" + and random() < self.params["prob_terminal"] + ): + node = Node( + depth=depth, + function_set=self.params["function_set"], + terminal_set=self.params["terminal_set"], + ) + node.value = choice(node.terminal_set) + + # Make function node + else: + node = Node( + depth=depth, + function_set=self.params["function_set"], + terminal_set=self.params["terminal_set"], + ) + node.value = choice(node.function_set) + + for i in range(node.value.__code__.co_argcount): # Check arity + root = self.grow_tree(max_depth, method, depth=depth + 1) + node.roots.append(root) + + return node + + +class LinearNode(Node): + """The parent node of the tree, from which a number of subtrees emerge, as defined + by the user. The linear node takes a weighted sum of the output from the subtrees and + also uses a bias value. The weights and the bias are calculated by the linear least + square technique. + + Parameters + ---------- + value : function, str or float + A function node has as its value a function. Terminal nodes contain variables which are either float or str. + depth : int + The depth the node is at. + params : None or dict + Parameters of the model. + """ + + def __init__(self, value="linear", depth=0, params=None): + super().__init__(params=params) + self.value = value + self.nodes_at_depth = {} + self.params = params + self.depth = depth + self.total_depth = None + self.out = None + self.complexity = None + self.fitness = None + self.linear = None + + def calculate_linear(self, X_train, y_train): + + sub_trees = [] + # Stack outputs of subtrees to form weight matrix + for root in self.roots: + sub_trees.append(root.predict(X_train)) + + sub_trees = np.hstack(sub_trees) + axis = None + if sub_trees.ndim > 1: + axis = 1 + sub_trees = np.insert(sub_trees, 0, 1, axis=axis) + + weights, *_ = np.linalg.lstsq(sub_trees, y_train, rcond=None) + self.linear = weights + out = np.dot(sub_trees, weights) + + # Error reduction ratio + q, r = np.linalg.qr(sub_trees) + s = np.linalg.lstsq(q, y_train, rcond=None)[0] + error = np.divide((s ** 2 * np.sum(q * q, axis=0)), np.sum(out * out, axis=0)) + + # If error reduction ration < err_lim, delete root and grow new one + for i, err in enumerate(error[1:]): + if err < self.params["error_lim"]: + del self.roots[i] + self.grow_tree( + max_depth=self.params["max_depth"], method="grow", ind=self + ) + + self.nodes = self.get_sub_nodes() + + num_func_nodes = sum(1 for node in self.nodes if callable(node.value)) + + complexity = ( + self.params["complexity_scalar"] * self.total_depth + + (1 - self.params["complexity_scalar"]) * num_func_nodes + ) + + self.out = out + self.complexity = complexity + training_error = None + + if self.params["loss_func"] == "root_mean_square": + training_error = np.sqrt(np.mean(((y_train - out) ** 2))) + + elif self.params["loss_func"] == "root_median_square": + training_error = np.sqrt(np.median(((y_train - out) ** 2))) + + return [training_error, self.complexity] diff --git a/pyrvea/Problem/dataproblem.py b/pyrvea/Problem/dataproblem.py new file mode 100644 index 0000000..dabbb13 --- /dev/null +++ b/pyrvea/Problem/dataproblem.py @@ -0,0 +1,190 @@ +from sklearn.gaussian_process import GaussianProcessRegressor +from sklearn.neural_network import MLPRegressor +from pyrvea.Problem.evonn_problem import EvoNNModel as EvoNN +from pyrvea.Problem.evodn2_problem import EvoDN2Model as EvoDN2 +from pyrvea.Problem.biogp_problem import BioGPModel as BioGP +from sklearn import preprocessing +from sklearn.model_selection import train_test_split as tts +import numpy as np +from sklearn.metrics import r2_score +from pyrvea.Problem.baseproblem import BaseProblem +import pandas as pd +from typing import List + + +class DataProblem(BaseProblem): + def __init__( + self, + data: pd.DataFrame = None, + x: List[str] = None, + y: List[str] = None, + minimize: List[bool] = None, + ideal: List[float] = None, + nadir: List[float] = None, + num_of_constraints=0, + lower_limits: List[float] = None, + upper_limits: List[float] = None, + name="data_problem", + ): + super().__init__() + self.raw_data = data + self.data = data + self.x = x + self.y = y + self.num_of_variables = len(x) + self.num_of_objectives = len(y) + self.num_of_constraints = num_of_constraints + self.number_of_samples = self.data.shape[0] + self.name = name + if minimize is None: + self.minimize = [True] * self.num_of_objectives + else: + assert len(minimize) == self.num_of_objectives + self.minimize = minimize + self.preprocessing_transformations = [] + # These indices define how the training will occur. + # all_indices is the list of indices that can be used. This does not include + # outliers. + self.all_indices = list(range(self.number_of_samples)) + # These should be list of lists. + # The inner list contains the list of indices. + # The outer list, if it contains multiple elements, should lead to multiple + # trained models. Can be used for k-fold validation. + # Train and test indices super list should have the same length. + self.train_indices: List[List] = [] + self.test_indices: List[List] = [] + self.validation_indices: List[List] = None + + # self.models = dict.fromkeys(self.y, []) # This method duplicates models in each key, why? + self.models = {} # This works.. + for obj in self.y: + self.models[obj] = [] + + self.metrics = [] + # Defining bounds in the decision space + if lower_limits is None: + self.lower_limits = np.min(self.raw_data[x], axis=0) + else: + assert len(lower_limits) == self.num_of_variables + self.lower_limits = lower_limits + if upper_limits is None: + self.upper_limits = np.max(self.raw_data[x], axis=0) + else: + assert len(upper_limits) == self.num_of_variables + self.upper_limits = upper_limits + + def data_scaling(self, data_decision): # Scales the data from 0 to 1 + # Check this range stuff + min_max_scaler = preprocessing.MinMaxScaler( + feature_range=(self.lower_limits, self.upper_limits) + ) + self.processed_data_decision = min_max_scaler.fit_transform(data_decision) + self.preprocessing_transformations.append(min_max_scaler) + + def data_uniform_mapping(self): # Maps the data to uniform distribution + pass + + def outlier_removal(self): # Removes the outliers + pass + + def train_test_split(self, train_size: float = 0.8): # Split dataset + + for x in range(1): + train_indices, test_indices = tts(self.all_indices, train_size=train_size) + train_indices.sort() + test_indices.sort() + self.train_indices.append(train_indices) + self.test_indices.append(test_indices) + + def train(self, model_type: str = None, objectives: str = None, **kwargs): + if objectives is None: + objectives = self.y + if model_type is None: + model_type = "MLP" + surrogate_model_options = { + "GPR": GaussianProcessRegressor, + "MLP": MLPRegressor, + "EvoNN": EvoNN, + "EvoDN2": EvoDN2, + "BioGP": BioGP + } + model_type = surrogate_model_options[model_type] + # Build specific surrogate models + print("Building Surrogate Models ...") + # Fit to data using Maximum Likelihood Estimation of the parameters + for obj in objectives: + + print("Building model for " + str(obj)) + for train_run, train_indices in enumerate(self.train_indices): + print("Training run number", train_run, "of", len(self.train_indices)) + model = model_type(**kwargs) + model.fit( + self.data[self.x].loc[train_indices], + self.data[obj].loc[train_indices], + ) + self.models[obj].append(model) + + # Select model + print("Surrogate models build completed.") + + def transform_new_data(self, decision_variables): + decision_variables_transformed = decision_variables + if len(self.preprocessing_transformations) > 0: + for transformation in self.preprocessing_transformations: + decision_variables_transformed = transformation.transfrom( + decision_variables_transformed + ) + return decision_variables_transformed + + def surrogates_predict(self, decision_variables): + y_pred = None + # transforms applied + decision_variables_transformed = self.transform_new_data(decision_variables) + for obj, i in zip(self.y, range(self.num_of_objectives)): + y = self.models[obj][0].predict( + decision_variables_transformed + ).reshape(-1, 1) + if y_pred is None: + y_pred = np.asarray(y) + else: + y_pred = np.hstack((y_pred, y)) + return y_pred + + def testing_score(self): # Return R-squared of testing + x, y = self.select_data(self.test_indices) + x = self.transform_new_data(x) + y_pred = None + for i in range(np.shape(x)[0]): + if y_pred is None: + y_pred = np.asarray(self.surrogates_predict(x[i])) + else: + y_pred = np.vstack((y_pred, self.surrogates_predict(x[i]))) + for i in range(np.shape(y)[1]): + self.r_sq.append(r2_score(y[:, i], y_pred[:, i])) + return y_pred + + def retrain_surrogate(self): + pass + + def objectives(self, decision_variables): + """Objectives function to use in optimization. + + Parameters + ---------- + decision_variables : ndarray + The decision variables + + Returns + ------- + objectives : ndarray + The objective values + + """ + objectives = [] + for obj in self.y: + objectives.append( + self.models[obj][0].predict(decision_variables.reshape(1, -1))[0] + ) + + return objectives + diff --git a/pyrvea/Problem/evodn2_problem.py b/pyrvea/Problem/evodn2_problem.py new file mode 100644 index 0000000..faa2875 --- /dev/null +++ b/pyrvea/Problem/evodn2_problem.py @@ -0,0 +1,616 @@ +from pyrvea.Problem.baseproblem import BaseProblem +from pyrvea.Population.Population import Population +from pyrvea.EAs.PPGA import PPGA +from scipy.special import expit +import numpy as np +import plotly +import plotly.graph_objs as go +import random + + +class EvoDN2(BaseProblem): + """Creates Deep Neural Networks (DNN) for the EvoDN2 algorithm. + + DNNs have a fixed number of subnets, each of which has a random number of + layers, and a random number of nodes in each layer, dependant on max layers + and max nodes set by user. + + Notes + ----- + The algorithm has been created earlier in MATLAB, and this Python implementation has been using + that code as a basis. + + Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + + Parameters + ---------- + name : str + Name of the problem + X_train : ndarray + Training data input + y_train : ndarray + Training data target values + num_of_objectives : int + The number of objectives + num_samples : int + The number of data points, or samples. + subsets : array_like + A list of variables used for each subnet of the model. + params : dict + Parameters for the models + + References + ---------- + [1] Swagata R., Bhupinder S., Chakrabarti, N. and Chakraborti, N. (2019). A new Deep Neural Network algorithm + employed in the study of mechanical properties of micro-alloyed steel. + Department of Metallurgical and Materials Engineering, Indian Institute of Technology. + """ + + def __init__( + self, + name=None, + X_train=None, + y_train=None, + num_of_objectives=2, + num_samples=None, + subsets=None, + params=None, + ): + super().__init__() + + self.name = name + self.X_train = X_train + self.y_train = y_train + self.num_of_objectives = num_of_objectives + self.num_samples = num_samples + self.subsets = subsets + self.params = params + + def objectives(self, decision_variables) -> list: + """ Use this method to calculate objective functions. + + Parameters + ---------- + decision_variables : ndarray + Variables from the neural network + Returns + ------- + obj_func : list + The objective function + """ + + non_linear_layer, complexity = self.activation(decision_variables) + _, predicted_values, training_error = self.calculate_linear(non_linear_layer) + + obj_func = [training_error, complexity] + + return obj_func + + def activation(self, decision_variables): + """ Calculates the dot product and applies the activation function. + Parameters + ---------- + decision_variables : ndarray + Array of all subnets in the current neural network + + Returns + ------- + non_linear_layer : ndarray + The final non-linear layer before the output + complexity : float + The complexity of the neural network + """ + network_complexity = [] + non_linear_layer = np.empty((self.num_samples, 0)) + + for i, subnet in enumerate(decision_variables): + + # Get the input variables for the first layer + in_nodes = self.X_train[:, self.subsets[i]] + subnet_complexity = 1 + + for layer in subnet: + # Calculate the dot product + bias + out = np.dot(in_nodes, layer[1:, :]) + layer[0] + + subnet_complexity = np.dot(subnet_complexity, np.abs(layer[1:, :])) + + in_nodes = self.activate(self.params["activation_func"], out) + + network_complexity.append(np.sum(subnet_complexity)) + non_linear_layer = np.hstack((non_linear_layer, in_nodes)) + + complexity = np.sum(network_complexity) + + return non_linear_layer, complexity + + def calculate_linear(self, activated_layer): + """ Apply the linear function to the final output layer + and calculate the training error. + + Parameters + ---------- + activated_layer : ndarray + Output of the activation function. + + Returns + ------- + linear_layer : ndarray + The optimized output layer of the network. + predicted_values : ndarray + The prediction of the model. + training_error : float + Training error of the model. + """ + + linear_layer = None + predicted_values = None + training_error = None + + if self.params["opt_func"] == "llsq": + linear_solution = np.linalg.lstsq(activated_layer, self.y_train, rcond=None) + linear_layer = linear_solution[0] + predicted_values = np.dot(activated_layer, linear_layer) + + if self.params["loss_func"] == "root_mean_square": + training_error = np.sqrt(np.mean(((self.y_train - predicted_values) ** 2))) + + elif self.params["loss_func"] == "root_median_square": + training_error = np.sqrt(np.median(((self.y_train - predicted_values) ** 2))) + + return linear_layer, predicted_values, training_error + + def select(self, pop, non_dom_front, selection="min_error"): + """ Select target model from the population. + + Parameters + ---------- + pop : obj + The population object. + non_dom_front : list + Indices of the models on the non-dominated front. + selection : str + The criterion to use for selecting the model. + Possible values: 'min_error', 'manual' + + Returns + ------- + model: + The selected model. + fitness: + The model's fitness values. + + """ + model = None + fitness = None + if selection == "min_error": + # Return the model with the lowest error + + lowest_error = np.argmin(pop.objectives[:, 0]) + model = pop.individuals[lowest_error] + fitness = pop.fitness[lowest_error] + + elif selection == "manual": + + pareto = pop.objectives[non_dom_front] + hover = pop.objectives[non_dom_front].tolist() + + for i, x in enumerate(hover): + x.insert(0, "Model " + str(non_dom_front[i]) + "
") + + trace0 = go.Scatter( + x=pop.objectives[:, 0], y=pop.objectives[:, 1], mode="markers" + ) + trace1 = go.Scatter( + x=pareto[:, 0], + y=pareto[:, 1], + text=hover, + hoverinfo="text", + mode="markers+lines", + ) + data = [trace0, trace1] + layout = go.Layout( + xaxis=dict(title="training error"), yaxis=dict(title="complexity") + ) + plotly.offline.plot( + {"data": data, "layout": layout}, + filename=self.name + "_training_models_" + "pareto" + ".html", + auto_open=True, + ) + + model_idx = None + while model_idx not in non_dom_front: + usr_input = input( + "Please input the number of the model of your preference: " + ) + try: + model_idx = int(usr_input) + except ValueError: + print("Invalid input, please enter the model number.") + continue + + if model_idx not in non_dom_front: + print("Model " + str(model_idx) + " not found.") + + model = pop.individuals[int(model_idx)] + fitness = pop.fitness[int(model_idx)] + + return model, fitness + + @staticmethod + def activate(name, x): + if name == "sigmoid": + return expit(x) + + if name == "relu": + return np.maximum(x, 0) + + if name == "tanh": + return np.tanh(x) + + +class EvoDN2Model(EvoDN2): + """Class for the EvoDN2 surrogate model. + + Parameters + ---------- + model_parameters : dict + Parameters passed for the model. + ea_parameters : dict + Parameters passed for the genetic algorithm. + + Attributes + ---------- + name : str + Name of the problem + subnets : array_like + A list containing the subnets of the model. + subsets : array_like + A list of variables used for each subnet of the model. + fitness : list + Fitness of the trained model. + non_linear_layer : np.ndarray or None + The activated layer combining all of the model's subnets. + linear_layer : np.ndarray or None + The final optimized layer of the network. + svr : array_like + Single variable response of the model. + log : file + If logging set to True in params, external log file is stored here. + + """ + + def __init__(self, model_parameters=None, ea_parameters=None): + super().__init__() + self.name = "EvoDN2_Model" + self.subnets = None + self.subsets = None + self.fitness = [] + self.non_linear_layer = None + self.linear_layer = None + self.svr = None + self.log = None + self.ea_params = ea_parameters + if model_parameters: + self.set_params(**model_parameters) + else: + self.set_params() + + def set_params( + self, + name="EvoDN2_Model", + training_algorithm=PPGA, + pop_size=500, + num_subnets=4, + max_layers=4, + max_nodes=4, + prob_omit=0.2, + w_low=-5.0, + w_high=5.0, + activation_func="sigmoid", + opt_func="llsq", + loss_func="root_mean_square", + selection="min_error", + recombination_type="evodn2_xover_mutation", + crossover_type="standard", + mutation_type="gaussian", + logging=False, + plotting=False + ): + """ Set parameters for EvoDN2 model. + + Parameters + ---------- + name : str + Name of the problem. + training_algorithm : EA + Which training algorithm to use. + pop_size : int + Population size. + num_subnets : int + Number of subnets. + max_layers : int + Maximum number of hidden layers in each subnet. + max_nodes : int + Maximum number of nodes in each hidden layer. + prob_omit : float + Probability of setting some weights to zero initially. + w_low : float + The lower bound for randomly generated weights. + w_high : float + The upper bound for randomly generated weights. + activation_func : str + Function to use for activation. + opt_func : str + Function to use for optimizing the final layer of the model. + loss_func : str + The loss function to use. + selection : str + The selection to use for selecting the model. + recombination_type, crossover_type, mutation_type : str + Recombination functions. If recombination_type is specified, crossover and mutation + will be handled by the same function. If None, they are done separately. + logging : bool + True to create a logfile, False otherwise. + plotting : bool + True to create a plot, False otherwise. + + """ + params = { + "name": name, + "training_algorithm": training_algorithm, + "pop_size": pop_size, + "num_subnets": num_subnets, + "max_layers": max_layers, + "max_nodes": max_nodes, + "prob_omit": prob_omit, + "w_low": w_low, + "w_high": w_high, + "activation_func": activation_func, + "opt_func": opt_func, + "loss_func": loss_func, + "selection": selection, + "crossover_type": crossover_type, + "mutation_type": mutation_type, + "recombination_type": recombination_type, + "logging": logging, + "plotting": plotting + } + + self.name = name + self.params = params + + def fit(self, training_data, target_values): + """Fit data in EvoDN2 model, divide input variables for each subnet randomly, + and train the model. + + Parameters + ---------- + training_data : pd.DataFrame, shape = (numbers of samples, number of variables) + Training data. + target_values : pd.DataFrame + Target values. + + Returns + ------- + self : returns an instance of self. + + """ + self.X_train = np.asarray(training_data) + self.y_train = np.asarray(target_values) + self.num_samples = target_values.shape[0] + self.num_of_variables = training_data.shape[1] + + self.subsets = [] + + # Create random subsets of decision variables for each subnet + + for i in range(self.params["num_subnets"]): + n = random.randint(1, self.X_train.shape[1]) + self.subsets.append(random.sample(range(self.X_train.shape[1]), n)) + + # Ensure that each decision variable is used as an input in at least one subnet + for n in list(range(self.X_train.shape[1])): + if not any(n in k for k in self.subsets): + self.subsets[random.randint(0, self.params["num_subnets"] - 1)].append( + n + ) + + self.train() + + self.single_variable_response(ploton=self.params["plotting"]) + + if self.params["logging"]: + self.create_logfile() + + return self + + def train(self): + """Create a random population, evolve it and select a model based on selection.""" + pop = Population( + self, + assign_type="EvoDN2", + pop_size=self.params["pop_size"], + recombination_type=self.params["recombination_type"], + crossover_type=self.params["crossover_type"], + mutation_type=self.params["mutation_type"], + plotting=self.params["plotting"], + ) + + pop.evolve( + EA=self.params["training_algorithm"], + ea_parameters=self.ea_params + ) + + non_dom_front = pop.non_dominated() + self.subnets, self.fitness = self.select( + pop, non_dom_front, self.params["selection"] + ) + self.non_linear_layer, _ = self.activation(self.subnets) + self.linear_layer, *_ = self.calculate_linear(self.non_linear_layer) + + def predict(self, decision_variables): + """Predict using the EvoDN2 model. + + Parameters + ---------- + decision_variables : pd.DataFrame + The decision variables used for prediction. + + Returns + ------- + y : ndarray + The prediction of the model. + + """ + non_linear_layer = np.empty((decision_variables.shape[0], 0)) + + for i, subnet in enumerate(self.subnets): + + in_nodes = np.asarray(decision_variables)[:, self.subsets[i]] + + for layer in subnet: + + out = np.dot(in_nodes, layer[1:, :]) + layer[0] + + in_nodes = self.activate(self.params["activation_func"], out) + + non_linear_layer = np.hstack((non_linear_layer, in_nodes)) + + y = np.dot(non_linear_layer, self.linear_layer) + + return y + + def plot(self, prediction, target, name=None): + """Creates and shows a plot for the model's prediction. + + Parameters + ---------- + prediction : np.ndarray + The prediction of the model. + target : pd.DataFrame + The target values. + name : str + Filename to save the plot as. + """ + target = np.asarray(target) + if name is None: + name = self.name + + trace0 = go.Scatter(x=prediction, y=target, mode="markers") + trace1 = go.Scatter(x=target, y=target) + data = [trace0, trace1] + plotly.offline.plot( + data, + filename="Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_nodes" + + str(self.params["num_subnets"]) + + "_" + + str(self.params["max_layers"]) + + "_" + + str(self.params["max_nodes"]) + + ".html", + auto_open=True, + ) + + def create_logfile(self, name=None): + """Create a log file containing the parameters for training the model and the EA. + + Returns + ------- + log_file : file + An external log file. + """ + + if name is None: + name = self.name + + # Save params to log file + log_file = open( + "Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_nodes" + + str(self.params["num_subnets"]) + + "_" + + str(self.params["max_layers"]) + + "_" + + str(self.params["max_nodes"]) + + ".log", + "a", + ) + + for i in self.params: + print("", i, ":", self.params[i], file=log_file) + + if self.fitness is not None: + print("fitness: " + str(self.fitness), file=log_file) + + if self.svr is not None: + print("single variable response: " + str(self.svr), file=log_file) + + return log_file + + def single_variable_response(self, ploton=False): + """Get the model's response to a single variable. + + Parameters + ---------- + ploton : bool + Create and show plot on/off. + + """ + + trend = np.loadtxt("trend") + avg = np.ones((1, self.num_of_variables)) * (np.finfo(float).eps + 1) / 2 + svr = np.empty((0, 2)) + variables = np.ones((len(trend), 1)) * avg + + for i in range(self.num_of_variables): + + variables[:, i] = trend + + out = self.predict(variables) + + if min(out) == max(out): + out = 0.5 * np.ones(out.size) + else: + out = (out - min(out)) / (max(out) - min(out)) + + if ploton: + trace0 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=variables[:, i], name="input" + ) + trace1 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=out, name="output" + ) + data = [trace0, trace1] + plotly.offline.plot( + data, filename="x" + str(i + 1) + "_response.html", auto_open=True + ) + + p = np.diff(out) + q = np.diff(trend) + r = np.multiply(p, q) + r_max = max(r) + r_min = min(r) + s = None + if r_max <= 0 and r_min <= 0: + s = "inverse" + elif r_max >= 0 and r_min >= 0: + s = "direct" + elif r_max == 0 and r_min == 0: + s = "nil" + elif r_min < 0 < r_max: + s = "mixed" + + svr = np.vstack((svr, ["x" + str(i + 1), s])) + self.svr = svr diff --git a/pyrvea/Problem/evonn_problem.py b/pyrvea/Problem/evonn_problem.py new file mode 100644 index 0000000..84dc356 --- /dev/null +++ b/pyrvea/Problem/evonn_problem.py @@ -0,0 +1,603 @@ +from pyrvea.Problem.baseproblem import BaseProblem +from pyrvea.Population.Population import Population +from pyrvea.EAs.PPGA import PPGA +from pyrvea.EAs.RVEA import RVEA +from scipy.special import expit +import numpy as np +import plotly +import plotly.graph_objs as go +from scipy.optimize import lsq_linear + + +class EvoNN(BaseProblem): + """Creates Artificial Neural Network (ANN) models for the EvoNN algorithm. + + These models contain only one hidden node layer. The lower part of the network + is optimized by a genetic algorithm, and the upper part is optimized by Linear Least Square + algorithm by default. + + Parameters + ---------- + name : str + Name of the problem. + X_train : np.ndarray + Training data input. + y_train : np.ndarray + Training data target values. + num_of_objectives : int + The number of objectives. + params : dict + Parameters for model training. + num_samples : int + The number of data points, or samples. + + Notes + ----- + The algorithm has been created earlier in MATLAB, and this Python implementation has been using + that code as a basis. + + Python code has been written by Niko Rissanen under the supervision of professor Nirupam Chakraborti. + + References + ---------- + [1] Chakraborti, N. (2014). Strategies for evolutionary data driven modeling in chemical and metallurgical Systems. + In Applications of Metaheuristics in Process Engineering (pp. 89-122). Springer, Cham. + [2] Pettersson, F., Chakraborti, N., & Saxén, H. (2007). A genetic algorithms based multi-objective neural net + applied to noisy blast furnace data. Applied Soft Computing, 7(1), 387-397. + + """ + + def __init__( + self, + name=None, + X_train=None, + y_train=None, + num_of_objectives=2, + params=None, + num_samples=None, + ): + super().__init__() + + self.name = name + self.X_train = X_train + self.y_train = y_train + self.num_of_objectives = num_of_objectives + self.params = params + self.num_samples = num_samples + + def objectives(self, decision_variables) -> list: + """ Use this method to calculate objective functions. + + Parameters + ---------- + decision_variables : np.ndarray + Variables from the neural network. + + Returns + ------- + obj_func : list + The objective function. + + """ + + activated_layer, complexity = self.activation(decision_variables) + _, _, training_error = self.calculate_linear(activated_layer) + + obj_func = [training_error, complexity] + + return obj_func + + def activation(self, non_linear_layer): + """ Calculates the dot product and applies the activation function. + Also get complexity for the lower part of the network. + + Parameters + ---------- + non_linear_layer : np.ndarray + Weight matrix of the neural network. + + Returns + ------- + activated_layer : np.ndarray + The activated non-linear layer before the output. + complexity : int + The model's complexity. + + """ + # Calculate the dot product + bias + out = np.dot(self.X_train, non_linear_layer[1:, :]) + non_linear_layer[0] + complexity = np.count_nonzero(non_linear_layer) + activated_layer = self.activate(self.params["activation_func"], out) + + return activated_layer, complexity + + def calculate_linear(self, non_linear_layer): + """ Apply the linear function to the activated layer + and calculate the training error. + + Parameters + ---------- + non_linear_layer : np.ndarray + Output of the activation function + + Returns + ------- + linear_layer : np.ndarray + The optimized weight matrix of the upper part of the network + predicted_values : np.ndarray + The prediction of the model + training_error : float + The model's training error + """ + + linear_layer = None + training_error = None + + if self.params["opt_func"] == "llsq": + linear_solution = np.linalg.lstsq( + non_linear_layer, self.y_train, rcond=None + ) + linear_layer = linear_solution[0] + + elif self.params["opt_func"] == "llsq_constrained": + linear_layer = lsq_linear(non_linear_layer, self.y_train, method='bvls', bounds=(0, 1)).x + + predicted_values = np.dot(non_linear_layer, linear_layer) + + if self.params["loss_func"] == "root_mean_square": + training_error = np.sqrt(np.mean(((self.y_train - predicted_values) ** 2))) + + elif self.params["loss_func"] == "root_median_square": + training_error = np.sqrt(np.median(((self.y_train - predicted_values) ** 2))) + + return linear_layer, predicted_values, training_error + + def information_criterion(self, decision_variables): + """Calculate the information criterion. + + Currently supports Akaike and corrected Akaike Information Criterion. + + Returns + ------- + Corrected Akaike Information criterion + """ + activated_layer, complexity = self.activation(decision_variables) + linear_layer, predicted_values, _ = self.calculate_linear(activated_layer) + rss = np.sum(((predicted_values - self.y_train) ** 2)) + k = complexity + np.count_nonzero(linear_layer) + aic = 2 * k + self.num_samples * np.log(rss / self.num_samples) + aicc = aic + (2 * k * (k + 1) / (self.num_samples - k - 1)) + + return aicc + + def select(self, pop, non_dom_front, selection="min_error"): + """ Select target model from the population. + + Parameters + ---------- + pop : obj + The population object. + non_dom_front : list + Indices of the models on the non-dominated front. + selection : str + The criterion to use for selecting the model. + Possible values: 'min_error', 'akaike_corrected', 'manual' + + Returns + ------- + The selected model + """ + model = None + fitness = None + if selection == "min_error": + # Return the model with the lowest error + + lowest_error = np.argmin(pop.objectives[:, 0]) + model = pop.individuals[lowest_error] + fitness = pop.fitness[lowest_error] + + elif selection == "akaike_corrected": + + # Calculate Akaike information criterion for the non-dominated front + # and return the model with the lowest value + + info_c_rank = [] + + for i in non_dom_front: + + info_c = self.information_criterion(pop.individuals[i]) + info_c_rank.append((info_c, i)) + + info_c_rank.sort() + + model = pop.individuals[info_c_rank[0][1]] + fitness = pop.fitness[info_c_rank[0][1]] + + elif selection == "manual": + + pareto = pop.objectives[non_dom_front] + hover = pop.objectives.tolist() + + for i, x in enumerate(hover): + x.insert(0, "Model " + str(i) + "
") + + trace0 = go.Scatter( + x=pop.objectives[:, 0], y=pop.objectives[:, 1], mode="markers" + ) + trace1 = go.Scatter( + x=pareto[:, 0], + y=pareto[:, 1], + text=hover, + hoverinfo="text", + mode="markers+lines", + ) + data = [trace0, trace1] + layout = go.Layout( + xaxis=dict(title="training error"), yaxis=dict(title="complexity") + ) + plotly.offline.plot( + {"data": data, "layout": layout}, + filename=self.name + "_training_models_" + "pareto" + ".html", + auto_open=True, + ) + + model_idx = None + while model_idx not in pop.objectives: + usr_input = input( + "Please input the number of the model of your preference: " + ) + try: + model_idx = int(usr_input) + except ValueError: + print("Invalid input, please enter the model number.") + continue + + if model_idx not in pop.objectives: + print("Model " + str(model_idx) + " not found.") + + model = pop.individuals[int(model_idx)] + fitness = pop.fitness[int(model_idx)] + + return model, fitness + + @staticmethod + def activate(name, x): + if name == "sigmoid": + return expit(x) + + if name == "relu": + return np.maximum(x, 0) + + if name == "tanh": + return np.tanh(x) + + +class EvoNNModel(EvoNN): + """The class for the EvoNN surrogate model. + + Parameters + ---------- + model_parameters : dict + Parameters passed for the model. + ea_parameters : dict + Parameters passed for the genetic algorithm. + + Attributes + ---------- + name : str + Name of the model. + non_linear_layer : np.ndarray + The weight matrix of the lower part of the network. + linear_layer : np.ndarray + The linear layer of the upper part of the network. + fitness : list + Fitness of the trained model. + svr : np.ndarray + Single variable response of the model. + log : file + If logging set to True in params, external log file is stored here. + + """ + + def __init__(self, model_parameters=None, ea_parameters=None): + super().__init__() + self.name = "EvoNN_Model" + self.non_linear_layer = None + self.linear_layer = None + self.fitness = None + self.svr = None + self.log = None + self.ea_params = ea_parameters + if model_parameters: + self.set_params(**model_parameters) + else: + self.set_params() + + def set_params( + self, + name="EvoNN_Model", + training_algorithm=PPGA, + pop_size=500, + num_nodes=20, + prob_omit=0.2, + w_low=-5.0, + w_high=5.0, + activation_func="sigmoid", + opt_func="llsq", + loss_func="root_median_square", + selection="akaike_corrected", + recombination_type="evonn_xover_mutation", + crossover_type="standard", + mutation_type="gaussian", + logging=False, + plotting=False, + ): + + """ Set parameters for the EvoNN model. + + Parameters + ---------- + name : str + Name of the problem. + training_algorithm : EA + Which evolutionary algorithm to use for training the models. + pop_size : int + Population size. + num_nodes : int + Maximum number of nodes per layer. + prob_omit : float + Probability of setting some weights to zero initially. + w_low : float + The lower bound for randomly generated weights. + w_high : float + The upper bound for randomly generated weights. + activation_func : str + Function to use for activation. + opt_func : str + Function to use for optimizing the final layer of the model. + loss_func : str + The loss function to use. + selection : str + The selection to use for selecting the model. + recombination_type, crossover_type, mutation_type : str or None + Recombination functions. If recombination_type is specified, crossover and mutation + will be handled by the same function. If None, they are done separately. + logging : bool + True to create a logfile, False otherwise. + plotting : bool + True to create a plot, False otherwise. + """ + + params = { + "name": name, + "training_algorithm": training_algorithm, + "pop_size": pop_size, + "num_nodes": num_nodes, + "prob_omit": prob_omit, + "w_low": w_low, + "w_high": w_high, + "activation_func": activation_func, + "opt_func": opt_func, + "loss_func": loss_func, + "selection": selection, + "recombination_type": recombination_type, + "crossover_type": crossover_type, + "mutation_type": mutation_type, + "logging": logging, + "plotting": plotting + } + + self.name = name + self.params = params + + def fit(self, training_data, target_values): + """Fit data in EvoNN model. + + Parameters + ---------- + training_data : pd.DataFrame, shape = (numbers of samples, number of variables) + Training data. + target_values : pd.DataFrame + Target values. + + Returns + ------- + self : returns an instance of self. + + """ + + self.X_train = np.asarray(training_data) + self.y_train = np.asarray(target_values) + self.num_samples = target_values.shape[0] + self.num_of_variables = training_data.shape[1] + + self.train() + + self.single_variable_response(ploton=self.params["plotting"]) + + if self.params["logging"]: + self.create_logfile() + + return self + + def train(self): + """Trains the networks and selects the best model from the non dominated front. + + """ + pop = Population( + self, + assign_type="EvoNN", + pop_size=self.params["pop_size"], + plotting=self.params["plotting"], + recombination_type=self.params["recombination_type"], + crossover_type=self.params["crossover_type"], + mutation_type=self.params["mutation_type"], + ) + pop.evolve( + EA=self.params["training_algorithm"], + ea_parameters=self.ea_params + + ) + + non_dom_front = pop.non_dominated() + self.non_linear_layer, self.fitness = self.select( + pop, non_dom_front, self.params["selection"] + ) + + activated_layer, _ = self.activation(self.non_linear_layer) + self.linear_layer, *_ = self.calculate_linear(activated_layer) + + def predict(self, decision_variables): + """Predict using the EvoNN model. + + Parameters + ---------- + decision_variables : pd.DataFrame + The decision variables used for prediction. + + Returns + ------- + y : np.ndarray + The prediction of the model. + + """ + out = ( + np.dot(np.asarray(decision_variables), self.non_linear_layer[1:, :]) + + self.non_linear_layer[0] + ) + + non_linear_layer = self.activate(self.params["activation_func"], out) # rename + + y = np.dot(non_linear_layer, self.linear_layer) + + return y + + def plot(self, prediction, target, name=None): + """Creates and shows a plot for the model's prediction. + + Parameters + ---------- + prediction : np.ndarray + The prediction of the model. + target : pd.DataFrame + The target values. + name : str + Filename to save the plot as. + """ + target = np.asarray(target) + if name is None: + name = self.name + + trace0 = go.Scatter(x=prediction, y=target, name="prediction", mode="markers") + trace1 = go.Scatter(x=target, y=target, name="target") + data = [trace0, trace1] + plotly.offline.plot( + data, + filename="Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_nodes" + + str(self.params["num_nodes"]) + + ".html", + auto_open=True, + ) + + def create_logfile(self, name=None): + """Create a log file containing the parameters for training the model and the EA. + + Parameters + ---------- + name : str + Filename to save the log as. + + Returns + ------- + log_file : file + An external log file. + """ + + if name is None: + name = self.name + + # Save params to log file + log_file = open( + "Tests/" + + self.params["training_algorithm"].__name__ + + self.__class__.__name__ + + name + + "_var" + + str(self.num_of_variables) + + "_nodes" + + str(self.params["num_nodes"]) + + ".log", + "a", + ) + + for i in self.params: + print("", i, ":", self.params[i], file=log_file) + + if self.fitness is not None: + print("fitness: " + str(self.fitness), file=log_file) + + if self.svr is not None: + print("single variable response: " + str(self.svr), file=log_file) + + return log_file + + def single_variable_response(self, ploton=False): + """Get the model's response to a single variable. + + Parameters + ---------- + ploton : bool + Create and show plot on/off. + """ + + trend = np.loadtxt("trend") + avg = np.ones((1, self.num_of_variables)) * (np.finfo(float).eps + 1) / 2 + svr = np.empty((0, 2)) + variables = np.ones((len(trend), 1)) * avg + + for i in range(self.num_of_variables): + + variables[:, i] = trend + + out = self.predict(variables) + + if min(out) == max(out): + out = 0.5 * np.ones(out.size) + else: + out = (out - min(out)) / (max(out) - min(out)) + + if ploton: + trace0 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=variables[:, i], name="input" + ) + trace1 = go.Scatter( + x=np.arange(len(variables[:, 1])), y=out, name="output" + ) + data = [trace0, trace1] + plotly.offline.plot( + data, filename="x" + str(i + 1) + "_response.html", auto_open=True + ) + + p = np.diff(out) + q = np.diff(trend) + r = np.multiply(p, q) + r_max = max(r) + r_min = min(r) + s = None + if r_max <= 0 and r_min <= 0: + s = "inverse" + elif r_max >= 0 and r_min >= 0: + s = "direct" + elif r_max == 0 and r_min == 0: + s = "nil" + elif r_min < 0 < r_max: + s = "mixed" + + svr = np.vstack((svr, ["x" + str(i + 1), s])) + self.svr = svr diff --git a/pyrvea/Problem/testProblem.py b/pyrvea/Problem/testProblem.py deleted file mode 100644 index 01b5f90..0000000 --- a/pyrvea/Problem/testProblem.py +++ /dev/null @@ -1,103 +0,0 @@ -from optproblems import dtlz, zdt -from pyrvea.Problem.baseProblem import baseProblem - - -class testProblem(baseProblem): - """Defines the problem.""" - - def __init__( - self, - name=None, - num_of_variables=None, - num_of_objectives=None, - num_of_constraints=0, - upper_limits=1, - lower_limits=0, - ): - """Pydocstring is ruthless. - - Args: - name: - num_of_variables: - num_of_objectives: - num_of_constraints: - upper_limits: - lower_limits: - """ - super(testProblem, self).__init__( - name, - num_of_variables, - num_of_objectives, - num_of_constraints, - upper_limits, - lower_limits, - ) - if name == "ZDT1": - self.obj_func = zdt.ZDT1() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "ZDT2": - self.obj_func = zdt.ZDT2() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "ZDT3": - self.obj_func = zdt.ZDT3() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "ZDT4": - self.obj_func = zdt.ZDT4() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "ZDT5": - self.obj_func = zdt.ZDT5() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "ZDT6": - self.obj_func = zdt.ZDT6() - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ1": - self.obj_func = dtlz.DTLZ1(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ2": - self.obj_func = dtlz.DTLZ2(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ3": - self.obj_func = dtlz.DTLZ3(num_of_objectives, num_of_variables) - self.lower_limits = 0 - self.upper_limits = 1 - elif name == "DTLZ4": - self.obj_func = dtlz.DTLZ4(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ5": - self.obj_func = dtlz.DTLZ5(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ6": - self.obj_func = dtlz.DTLZ6(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - elif name == "DTLZ7": - self.obj_func = dtlz.DTLZ7(num_of_objectives, num_of_variables) - self.lower_limits = self.obj_func.min_bounds - self.upper_limits = self.obj_func.max_bounds - - def objectives(self, decision_variables) -> list: - """Use this method to calculate objective functions. - - Args: - decision_variables: - """ - return self.obj_func(decision_variables) - - def constraints(self, decision_variables, objective_variables): - """Calculate constraint violation. - - Args: - decision_variables: - objective_variables: - """ - print("Error: Constraints not supported yet.") diff --git a/pyrvea/Problem/test_functions.py b/pyrvea/Problem/test_functions.py new file mode 100644 index 0000000..8272086 --- /dev/null +++ b/pyrvea/Problem/test_functions.py @@ -0,0 +1,286 @@ +import numpy as np +import pandas as pd +from pyDOE import lhs +from pyrvea.Problem.baseproblem import BaseProblem + + +class OptTestFunctions: + + """Test functions for single/multi-objective problems to test + the performance of evolutionary algorithms. + + See: https://en.wikipedia.org/wiki/Test_functions_for_optimization + + Parameters + ---------- + name : str + name of the test function + num_of_variables : int + number of decision variables + num_of_objectives : int + number of objectives + num_of_constraints : int + number of constraints + upper_limits : float + upper boundaries for test data + lower_limits : float + lower boundaries for test data + """ + + def __init__(self, name=None, num_of_variables=None): + self.name = name + self.num_of_variables = num_of_variables + # Define search domain for test functions + test_f_params = { + # Single objective functions + "Sphere": {"var": 2, "obj": 1, "bounds": (-5, 5)}, + "Matyas": {"var": 2, "obj": 1, "bounds": (-10, 10)}, + "Himmelblau": {"var": 2, "obj": 1, "bounds": (-5, 5)}, + "Rastigrin": {"var": 2, "obj": 1, "bounds": (-5.12, 5.12)}, + "Three-hump camel": {"var": 2, "obj": 1, "bounds": (-5, 5)}, + "Goldstein-Price": {"var": 2, "obj": 1, "bounds": (-2, 2)}, + "LeviN13": {"var": 2, "obj": 1, "bounds": (-10, 10)}, + "SchafferN2": {"var": 2, "obj": 1, "bounds": (-100, 100)}, + # Multi-objective functions + "Coello_ex1": {"var": 2, "obj": 2, "bounds": (0, 1)}, + "Fonseca-Fleming": {"var": 2, "obj": 2, "bounds": (-4, 4)}, + "Kursawe": {"var": 2, "obj": 2, "bounds": (-5, 5)}, + "SchafferN1": {"var": 1, "obj": 2, "bounds": (-100, 100)}, + } + + if self.name in test_f_params.keys(): + if self.num_of_variables is None: + self.num_of_variables = test_f_params[self.name]["var"] + self.num_of_objectives = test_f_params[self.name]["obj"] + self.lower_limits = test_f_params[self.name]["bounds"][0] + self.upper_limits = test_f_params[self.name]["bounds"][1] + + def __call__(self, x): + return self.objectives(x) + + def objectives(self, decision_variables) -> list: + """Use this method to calculate objective functions. + + Parameters + ---------- + decision_variables : np.ndarray + The decision variables. + + Returns + ------- + The objective functions. + + """ + # Single objective test functions + + if self.name == "Sphere": + # Sphere function, -5 <= x <= 5 + + x = np.asarray(decision_variables) + self.obj_func = sum(x ** 2) + + elif self.name == "Matyas": + # Matyas function, -10 <= x, y <= 10 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = 0.26 * (x ** 2 + y ** 2) - 0.48 * x * y + + elif self.name == "Himmelblau": + # Himmelblau's function, -5 <= x, y <= 5 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = (x ** 2 + y - 11) ** 2 + (x + y ** 2 - 7) ** 2 + + elif self.name == "Rastigrin": + # Rastigrin function, -5.12 <= x <= 5.12 + + x = np.asarray(decision_variables) + n = len(x) + self.obj_func = 10 * n + sum(x ** 2 - 10 * np.cos(2 * np.pi * x)) + + elif self.name == "Three-hump camel": + # Three-hump camel function, -5 <= x, y <= 5 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = 2 * x ** 2 - 1.05 * x ** 4 + (x ** 6) / 6 + x * y + y ** 2 + + elif self.name == "Goldstein-Price": + # Goldstein-Price function, -2 <= x, y <= 2 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = ( + 1 + + (x + y + 1) ** 2 + * (19 - 14 * x + 3 * (x ** 2) - 14 * y + 6 * x * y + 3 * (y ** 2)) + ) * ( + 30 + + (2 * x - 3 * y) ** 2 + * (18 - 32 * x + 12 * (x ** 2) + 48 * y - 36 * x * y + 27 * (y ** 2)) + ) + + elif self.name == "LeviN13": + # Levi function N.13, -10 <= x, y <= 10 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = ( + np.sin(3 * np.pi * x) ** 2 + + (x - 1) ** 2 * (1 + np.sin(3 * np.pi * y) ** 2) + + (y - 1) ** 2 * (1 + np.sin(2 * np.pi * y) ** 2) + ) + + elif self.name == "SchafferN2": + # Schaffer function N. 2, -100 <= x, y <= 100 + + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + self.obj_func = ( + 0.5 + + (np.sin((x ** 2 - y ** 2) ** 2) - 0.5) + / (1 + 0.001 * (x ** 2 + y ** 2)) ** 2 + ) + + # Test functions for multi-objective optimization + + elif self.name == "Coello_ex1": + x = np.asarray(decision_variables[0]) + y = np.asarray(decision_variables[1]) + a = 2 + q = 4 + f1 = x + f2 = (1 + 10 * y) * ( + 1 + - (x / (1 + 10 * y)) ** a + - x / (1 + 10 * y) * np.sin(2 * np.pi * q * x) + ) + + self.obj_func = [f1, f2] + + elif self.name == "Kursawe": + x1 = np.asarray(decision_variables[0]) + x2 = np.asarray(decision_variables[1]) + x3 = np.asarray(decision_variables[1]) + f1 = -10 * np.exp(-0.2 * np.sqrt(x1 ** 2 + x2 ** 2)) - 10 * np.exp( + -0.2 * np.sqrt(x2 ** 2 + x3 ** 2) + ) + f2 = ( + abs(x1) ** 0.8 + + 5.0 * np.sin(x1 ** 3) + + abs(x2) ** 0.8 + + 5.0 * np.sin(x2 ** 3) + + abs(x3) ** 0.8 + + 5.0 * np.sin(x3 ** 3) + ) + self.obj_func = [f1, f2] + + elif self.name == "Fonseca-Fleming": + f1 = 0 + f2 = 0 + + for n in range(len(decision_variables)): + f1 += ( + decision_variables[n] - 1 / np.sqrt(len(decision_variables)) + ) ** 2 + f2 += ( + decision_variables[n] + 1 / np.sqrt(len(decision_variables)) + ) ** 2 + + f1 = 1 - np.exp(-f1) + f2 = 1 - np.exp(-f2) + + self.obj_func = [f1, f2] + + elif self.name == "SchafferN1": + x = np.asarray(decision_variables[0]) + + f1 = x ** 2 + f2 = (x - 2) ** 2 + + self.obj_func = [f1, f2] + + return self.obj_func + + def create_training_data(self, samples=150, method="random", seed=None): + """Create training data for test functions. + + Parameters + ---------- + samples : int + number of samples + method : str + method to use in data creation. Possible values random, lhs, linear, linear+zeros, linear+reverse. + seed : int + if a number is given, random data will be seeded + """ + + np.random.seed(seed) + training_data_input = None + + if method == "random": + + training_data_input = np.random.uniform( + self.lower_limits, self.upper_limits, (samples, self.num_of_variables) + ) + + elif method == "lhs": + + training_data_input = lhs(self.num_of_variables, samples) * ( + abs(self.upper_limits) + abs(self.lower_limits) + ) - abs(self.upper_limits) + + elif method == "linear": + + training_data_input = np.linspace( + (self.lower_limits, self.lower_limits), + (self.upper_limits, self.upper_limits), + samples, + ) + + elif method == "linear+zeros": + + training_data_input = np.linspace( + (self.lower_limits, self.lower_limits), + (self.upper_limits, self.upper_limits), + samples, + ) + tmp = np.linspace(self.upper_limits, 0, samples) + x2 = np.zeros_like(tmp) + training_data_input = np.vstack( + (np.hstack((tmp, tmp)), np.hstack((tmp, x2))) + ).T + + elif method == "linear+reverse": + + np.linspace( + (self.lower_limits, self.lower_limits), + (self.upper_limits, self.upper_limits), + samples, + ) + tmp = np.linspace(self.upper_limits, 0, samples) + x2 = np.flip(tmp) + training_data_input = np.vstack( + (np.hstack((tmp, tmp)), np.hstack((tmp, x2))) + ).T + + training_data_output = np.asarray( + [self.objectives(x) for x in training_data_input] + ) + + # Convert numpy array into pandas dataframe, and make columns for it + data = np.hstack((training_data_input, training_data_output)) + dataset = pd.DataFrame.from_records(data) + x = [] + y = [] + for var in range(training_data_input.shape[1]): + x.append("x" + str(var + 1)) + for obj in range(training_data_output.shape[1]): + y.append("f" + str(obj + 1)) + dataset.columns = x + y + + np.random.seed(None) + + return dataset, x, y diff --git a/pyrvea/Problem/testproblem.py b/pyrvea/Problem/testproblem.py new file mode 100644 index 0000000..017ac2f --- /dev/null +++ b/pyrvea/Problem/testproblem.py @@ -0,0 +1,189 @@ +from optproblems import dtlz, zdt +from pyrvea.Problem.baseproblem import BaseProblem +from pyrvea.Problem.test_functions import OptTestFunctions +import numpy as np +import pandas as pd +from pyDOE import lhs +from sklearn.preprocessing import minmax_scale + + +class TestProblem(BaseProblem): + """Test functions for single/multi-objective problems to test + the performance of evolutionary algorithms. + + See: https://en.wikipedia.org/wiki/Test_functions_for_optimization + + Parameters + ---------- + name : str + Name of the test function. + num_of_variables : int + Number of decision variables. + num_of_objectives : int + Number of objectives. + num_of_constraints : int + Number of constraints. + upper_limits : float + Upper boundaries for test data. + lower_limits : float + Lower boundaries for test data. + """ + + def __init__( + self, + name=None, + num_of_variables=None, + num_of_objectives=None, + num_of_constraints=0, + upper_limits=1.0, + lower_limits=0.0, + ): + + super().__init__( + name, + num_of_variables, + num_of_objectives, + num_of_constraints, + upper_limits, + lower_limits, + ) + if name == "ZDT1": + self.obj_func = zdt.ZDT1() + + elif name == "ZDT2": + self.obj_func = zdt.ZDT2() + + elif name == "ZDT3": + self.obj_func = zdt.ZDT3() + + elif name == "ZDT4": + self.obj_func = zdt.ZDT4() + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "ZDT5": + self.obj_func = zdt.ZDT5() + + elif name == "ZDT6": + self.obj_func = zdt.ZDT6() + + elif name == "DTLZ1": + self.obj_func = dtlz.DTLZ1(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "DTLZ2": + self.obj_func = dtlz.DTLZ2(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "DTLZ3": + self.obj_func = dtlz.DTLZ3(num_of_objectives, num_of_variables) + self.lower_limits = 0 + self.upper_limits = 1 + elif name == "DTLZ4": + self.obj_func = dtlz.DTLZ4(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "DTLZ5": + self.obj_func = dtlz.DTLZ5(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "DTLZ6": + self.obj_func = dtlz.DTLZ6(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + elif name == "DTLZ7": + self.obj_func = dtlz.DTLZ7(num_of_objectives, num_of_variables) + self.lower_limits = self.obj_func.min_bounds + self.upper_limits = self.obj_func.max_bounds + else: + self.obj_func = OptTestFunctions( + name=self.name, + num_of_variables=num_of_variables, + ) + self.lower_limits = self.obj_func.lower_limits + self.upper_limits = self.obj_func.upper_limits + self.num_of_variables = self.obj_func.num_of_variables + self.num_of_objectives = self.obj_func.num_of_objectives + + def objectives(self, decision_variables) -> list: + """Use this method to calculate objective functions. + + Args: + decision_variables: + """ + return self.obj_func(decision_variables) + + def constraints(self, decision_variables, objective_variables): + """Calculate constraint violation. + + Args: + decision_variables: + objective_variables: + """ + print("Error: Constraints not supported yet.") + + def create_training_data(self, samples=500, method="random", seed=None): + """Create training data for test functions. + + Parameters + ---------- + samples : int + Number of samples. + method : str + Method to use in data creation. Possible values random, lhs (latin hypercube sampling), linear. + seed : int + If a number is given, random data will be seeded. + + Returns + ------- + dataset : Training data in a Pandas DataFrame, including all variables and objectives. + x : List of variables + y : List of objectives + + """ + + np.random.seed(seed) + training_data_input = None + + if method == "random": + + training_data_input = np.random.uniform( + self.lower_limits, self.upper_limits, (samples, self.num_of_variables) + ) + + elif method == "lhs": + # Latin Hypercube Sampling + + training_data_input = lhs(self.num_of_variables, samples) + training_data_input = np.round( + minmax_scale( + training_data_input, (self.lower_limits, self.upper_limits) + ), + decimals=5, + ) + + elif method == "linear": + + training_data_input = np.linspace( + self.lower_limits, self.upper_limits, samples + ) + + training_data_output = np.asarray( + [self.objectives(x) for x in training_data_input] + ) + if self.num_of_objectives == 1: + training_data_output = training_data_output[:, None] + + # Convert numpy array into pandas dataframe, and make columns for it + data = np.hstack((training_data_input, training_data_output)) + dataset = pd.DataFrame.from_records(data) + x = [] + y = [] + for var in range(training_data_input.shape[1]): + x.append("x" + str(var + 1)) + for obj in range(training_data_output.shape[1]): + y.append("f" + str(obj + 1)) + dataset.columns = x + y + + np.random.seed(None) + + return dataset, x, y diff --git a/pyrvea/Recombination/biogp_mutation.py b/pyrvea/Recombination/biogp_mutation.py new file mode 100644 index 0000000..11711f6 --- /dev/null +++ b/pyrvea/Recombination/biogp_mutation.py @@ -0,0 +1,82 @@ +import numpy as np +from random import choice, sample + + +def mutate( + offspring, + individuals, + params, + *args +): + """Perform BioGP mutation functions. + + Standard mutation: + Randomly select and regrow a subtree of an individual. + + Small mutation: + Randomly select a node within a tree and replace it with either a function of the same arity, + or another value from the terminal set. + + Mono parental: + Randomly swap two subtrees within the same individual. + + Parameters + ---------- + offspring : list + List of individuals to mutate. + individuals : list + List of all individuals. + params : dict + Parameters for breeding. If None, use defaults. + + """ + + prob_mut = params.get("prob_mutation", 0.3) + prob_stand = 1/3 * prob_mut + prob_point = 1/3 * prob_mut + prob_mono = prob_mut - prob_stand - prob_point + prob_replace = prob_mut + r = np.random.rand() + + for ind in offspring: + if r <= prob_stand: + # Standard mutation + # + # This picks a random subtree anywhere within the tree + rand_node = choice(ind.nodes[1:]) + tree = ind.grow_tree(method="grow", depth=rand_node.depth, ind=rand_node) + rand_node.value = tree.value + rand_node.roots = tree.roots + + # This picks a whole subtree at depth=1 under the linear node + # rand_subtree = np.random.randint(len(ind.roots)) + # del ind.roots[rand_subtree] + # ind.grow_tree(method="grow", ind=ind) + + ind.nodes = ind.get_sub_nodes() + + elif r <= prob_point + prob_stand: + # Small mutation + for node in ind.nodes[1:]: + if np.random.rand() < prob_replace and callable(node.value): + value = choice(node.function_set) + while node.value.__code__.co_argcount != value.__code__.co_argcount: + value = choice(node.function_set) + node.value = value + elif np.random.rand() < prob_replace: + node.value = choice(node.terminal_set) + ind.nodes = ind.get_sub_nodes() + + elif r <= prob_mono + prob_point + prob_stand: + # Mono parental + swap_nodes = sample(ind.nodes[1:], 2) + tmp_value = swap_nodes[0].value + tmp_roots = swap_nodes[0].roots + swap_nodes[0].value = swap_nodes[1].value + swap_nodes[0].roots = swap_nodes[1].roots + swap_nodes[1].value = tmp_value + swap_nodes[1].roots = tmp_roots + ind.nodes = ind.get_sub_nodes() + + else: + pass diff --git a/pyrvea/Recombination/biogp_xover.py b/pyrvea/Recombination/biogp_xover.py new file mode 100644 index 0000000..edac7e2 --- /dev/null +++ b/pyrvea/Recombination/biogp_xover.py @@ -0,0 +1,82 @@ +import numpy as np +from copy import deepcopy +from random import choice + + +def mate(mating_pop, individuals: list, params): + """Perform BioGP crossover functions. Produce two offsprings by swapping genetic + material of the two parents. + + Standard crossover: + Swap two random subtrees between the parents. + + Height-fair crossover: + Swap two random subtrees between the parents at the selected depth. + + Parameters + ---------- + mating_pop : list + List of indices of individuals to mate. If None, choose from population randomly. + Each entry should contain two indices, one for each parent. + individuals : list + List of all individuals. + params : dict + Parameters for evolution. If None, use defaults. + + Returns + ------- + offspring : list + The offsprings produced as a result of crossover. + """ + + prob_crossover = params.get("prob_crossover", 0.9) + + prob_standard = 0.5 + prob_height_fair = prob_crossover - prob_standard + r = np.random.rand() + + if mating_pop is None: + mating_pop = [] + for i in range(len(individuals)): + mating_pop.append([i, np.random.randint(len(individuals))]) + + offspring = [] + + for mates in mating_pop: + + offspring1 = deepcopy(individuals[mates[0]]) + offspring2 = deepcopy(individuals[mates[1]]) + + # Height-fair xover + if r <= prob_height_fair: + depth = min(offspring1.total_depth, offspring2.total_depth) + rand_node1 = choice(offspring1.nodes_at_depth[depth]) + rand_node2 = choice(offspring2.nodes_at_depth[depth]) + tmp_value = rand_node1.value + tmp_roots = rand_node1.roots + rand_node1.value = rand_node2.value + rand_node1.roots = rand_node2.roots + rand_node2.value = tmp_value + rand_node2.roots = tmp_roots + offspring1.nodes = offspring1.get_sub_nodes() + offspring2.nodes = offspring2.get_sub_nodes() + + # Standard xover + elif r <= prob_height_fair + prob_standard: + rand_node1 = choice(offspring1.nodes[1:]) # Exclude linear node + rand_node2 = choice(offspring2.nodes[1:]) + tmp_value = rand_node1.value + tmp_roots = rand_node1.roots + rand_node1.value = rand_node2.value + rand_node1.roots = rand_node2.roots + rand_node2.value = tmp_value + rand_node2.roots = tmp_roots + offspring1.nodes = offspring1.get_sub_nodes() + offspring2.nodes = offspring2.get_sub_nodes() + + else: + pass + + offspring.extend((offspring1, offspring2)) + + return offspring diff --git a/pyrvea/Recombination/bounded_polynomial_mutation.py b/pyrvea/Recombination/bounded_polynomial_mutation.py new file mode 100644 index 0000000..cc418d2 --- /dev/null +++ b/pyrvea/Recombination/bounded_polynomial_mutation.py @@ -0,0 +1,55 @@ +import numpy as np + + +def mutate(offspring, individuals, params, lower_limits, upper_limits): + """Bounded polynomial mutation. + + Parameters + ---------- + offspring : List + List of offspring to mutate. + individuals : List + List of all individuals. + params : dict + Parameters used for breeding. + lower_limits : float + Problem lower bounds. + upper_limits : float + Problem upper bounds. + + """ + dis_mutation = params.get("dis_mutation", 20) + + prob_mutation = 1 / np.array(individuals).shape[1] + + min_val = np.ones_like(offspring) * lower_limits + max_val = np.ones_like(offspring) * upper_limits + k = np.random.random(offspring.shape) + miu = np.random.random(offspring.shape) + temp = np.logical_and((k <= prob_mutation), (miu < 0.5)) + offspring_scaled = (offspring - min_val) / (max_val - min_val) + offspring[temp] = offspring[temp] + ( + (max_val[temp] - min_val[temp]) + * ( + ( + 2 * miu[temp] + + (1 - 2 * miu[temp]) * (1 - offspring_scaled[temp]) ** (dis_mutation + 1) + ) + ** (1 / (dis_mutation + 1)) + - 1 + ) + ) + temp = np.logical_and((k <= prob_mutation), (miu >= 0.5)) + offspring[temp] = offspring[temp] + ( + (max_val[temp] - min_val[temp]) + * ( + 1 + - ( + 2 * (1 - miu[temp]) + + 2 * (miu[temp] - 0.5) * offspring_scaled[temp] ** (dis_mutation + 1) + ) + ** (1 / (dis_mutation + 1)) + ) + ) + offspring[offspring > max_val] = max_val[offspring > max_val] + offspring[offspring < min_val] = min_val[offspring < min_val] \ No newline at end of file diff --git a/pyrvea/Recombination/evodn2_xover_mutation.py b/pyrvea/Recombination/evodn2_xover_mutation.py new file mode 100644 index 0000000..511782c --- /dev/null +++ b/pyrvea/Recombination/evodn2_xover_mutation.py @@ -0,0 +1,114 @@ +import numpy as np +from copy import deepcopy + + +def mate(mating_pop, individuals: list, params, crossover_type=None, mutation_type=None): + """Swap nodes between two partners and mutate based on standard deviation. + + Parameters + ---------- + mating_pop : list + List of indices of individuals to mate. If None, choose from population randomly. + Each entry should contain two indices, one for each parent. + individuals : list + List of all individuals. + params : dict + Parameters for evolution. If None, use defaults. + + Returns + ------- + offspring : list + The offsprings produced as a result of crossover and mutation. + """ + + prob_crossover = params.get("prob_crossover", 0.8) + prob_mutation = params.get("prob_mutation", 0.3) + mut_strength = params.get("mut_strength", 1.) + cur_gen = params.get("current_total_gen_count", 1) + total_gen = params.get("total_generations", 10) + std_dev = (5 / 3) * (1 - cur_gen / total_gen) + if std_dev < 0: + std_dev = 0 + + if mating_pop is None: + mating_pop = [] + for i in range(len(individuals)): + mating_pop.append([i, np.random.randint(len(individuals))]) + + offspring = [] + + # Gaussian + if mutation_type == "gaussian" or mutation_type is None: + + for mates in mating_pop: + + offspring1, offspring2 = ( + deepcopy(individuals[mates[0]]), + deepcopy(individuals[mates[1]]), + ) + + for subnet in range(len(offspring1)): + + sub1 = offspring1[subnet] + sub2 = offspring2[subnet] + + for layer in range(max(len(sub1), len(sub2))): + + try: + connections = min(sub1[layer].size, sub2[layer].size) + + # Crossover + exchange = np.random.choice( + connections, + np.random.binomial(connections, prob_crossover), + replace=False, + ) + tmp = np.copy(sub1[layer]) + sub1[layer].ravel()[exchange] = sub2[layer].ravel()[exchange] + sub2[layer].ravel()[exchange] = tmp.ravel()[exchange] + + except IndexError: + pass + + # Mutate the first offspring + try: + connections = sub1[layer].size + + mut_val = np.random.normal(0, std_dev, connections) * mut_strength + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + sub1[layer].ravel()[mut] += ( + sub1[layer].ravel()[mut] * mut_val[mut] + ) + + except IndexError: + pass + + # Mutate the second offspring + try: + connections = sub2[layer].size + + mut_val = np.random.normal(0, std_dev, connections) * mut_strength + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + sub2[layer].ravel()[mut] += ( + sub2[layer].ravel()[mut] * mut_val[mut] + ) + + except IndexError: + continue + + offspring.extend((offspring1, offspring2)) + + else: + pass + + return offspring diff --git a/pyrvea/Recombination/evonn_xover_mutation.py b/pyrvea/Recombination/evonn_xover_mutation.py new file mode 100644 index 0000000..2329460 --- /dev/null +++ b/pyrvea/Recombination/evonn_xover_mutation.py @@ -0,0 +1,114 @@ +import numpy as np + + +def mate(mating_pop, individuals: list, params, crossover_type=None, mutation_type=None): + """Swap nodes between two partners and mutate based on standard deviation. + + Parameters + ---------- + mating_pop : list + List of indices of individuals to mate. If None, choose from population randomly. + Each entry should contain two indices, one for each parent. + individuals : list + List of all individuals. + params : dict + Parameters for evolution. If None, use defaults. + + Returns + ------- + offspring : list + The offsprings produced as a result of crossover and mutation. + """ + + prob_crossover = params.get("prob_crossover", 0.8) + prob_mutation = params.get("prob_mutation", 0.3) + mut_strength = params.get("mut_strength", 1.) + cur_gen = params.get("current_total_gen_count", 1) + total_gen = params.get("total_generations", 10) + std_dev = (5 / 3) * (1 - cur_gen / total_gen) + if std_dev < 0: + std_dev = 0 + + if mating_pop is None: + mating_pop = [] + for i in range(len(individuals)): + mating_pop.append([i, np.random.randint(len(individuals))]) + + offspring = [] + + for mates in mating_pop: + + offspring1 = np.copy(individuals[mates[0]]) + offspring2 = np.copy(individuals[mates[1]]) + + # Crossover + for i in range(offspring1.shape[1]): + if np.random.random() < prob_crossover: + tmp = np.copy(offspring1[:, i]) + offspring1[:, i] = offspring2[:, i] + offspring2[:, i] = tmp + + if mutation_type == "gaussian" or mutation_type is None: + # Method : Gaussian (default) + # Take a random number of connections based on probability and mutate based on + # standard deviation, calculated once per generation. + + connections = offspring1.size + + mut_val = np.random.normal(0, std_dev, connections) * mut_strength + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + offspring1.ravel()[mut] += offspring1.ravel()[mut] * mut_val[mut] + + mut_val = np.random.normal(0, std_dev, connections) * mut_strength + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + offspring2.ravel()[mut] += offspring2.ravel()[mut] * mut_val[mut] + + elif mutation_type == "self-adapting": + # Method: Self adapting mutation + # Choose two random individuals and a random number of connections, + # mutate offspring based on current gen and connections of two randomly chosen individuals + + # Randomly select two individuals with current match active (=non-zero) + connections = offspring1.size + select = np.asarray(individuals)[ + np.random.choice(np.nonzero(np.asarray(individuals))[0], 2) + ] + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + offspring1.ravel()[mut] = offspring1.ravel()[mut] + mut_strength * ( + 1 - cur_gen / total_gen + ) * (select[1].ravel()[mut] - select[0].ravel()[mut]) + + select = np.asarray(individuals)[ + np.random.choice(np.nonzero(np.asarray(individuals))[0], 2) + ] + + mut = np.random.choice( + connections, + np.random.binomial(connections, prob_mutation), + replace=False, + ) + offspring2.ravel()[mut] = offspring2.ravel()[mut] + mut_strength * ( + 1 - cur_gen / total_gen + ) * (select[1].ravel()[mut] - select[0].ravel()[mut]) + + else: + pass + + offspring.extend((offspring1, offspring2)) + + return offspring diff --git a/pyrvea/Recombination/simulated_binary_crossover.py b/pyrvea/Recombination/simulated_binary_crossover.py new file mode 100644 index 0000000..1c03a72 --- /dev/null +++ b/pyrvea/Recombination/simulated_binary_crossover.py @@ -0,0 +1,50 @@ +import numpy as np +from random import shuffle + + +def mate(mating_pop, pop, params): + """Simulated binary crossover. + + Parameters + ---------- + mating_pop : list + List of population to mate. + pop : list + List of all individuals + params : dict + Parameters for breeding. If None, use defaults. + + Returns + ------- + offspring : List + The offspring produced as a result of crossover. + """ + prob_crossover = params.get("prob_crossover", 1) + dis_crossover = params.get("dis_crossover", 30) + + pop = np.asarray(pop) + pop_size, num_var = pop.shape + + if mating_pop is None: + shuffled_ids = list(range(pop_size)) + shuffle(shuffled_ids) + # Create random pairs from the population for mating + mating_pop = [shuffled_ids[i * 2: (i + 1) * 2] for i in range(int(len(shuffled_ids) / 2))] + + # The rest closely follows the matlab code. + + offsprings = np.zeros((0, num_var)) # empty_like() more efficient? + + for i in range(len(mating_pop)): + beta = np.zeros(num_var) + miu = np.random.rand(num_var) + beta[miu <= 0.5] = (2 * miu[miu <= 0.5]) ** (1 / (dis_crossover + 1)) + beta[miu > 0.5] = (2 - 2 * miu[miu > 0.5]) ** (-1 / (dis_crossover + 1)) + beta = beta * ((-1) ** np.random.randint(0, high=2, size=num_var)) + beta[np.random.rand(num_var) > prob_crossover] = 1 # It was in matlab code + avg = (pop[mating_pop[i][0]] + pop[mating_pop[i][1]]) / 2 + diff = (pop[mating_pop[i][0]] - pop[mating_pop[i][1]]) / 2 + offsprings = np.vstack((offsprings, avg+beta*diff)) + offsprings = np.vstack((offsprings, avg - beta * diff)) + + return offsprings diff --git a/pyrvea/Selection/APD_select.py b/pyrvea/Selection/APD_select.py index 4030424..11c114c 100644 --- a/pyrvea/Selection/APD_select.py +++ b/pyrvea/Selection/APD_select.py @@ -39,6 +39,9 @@ def APD_select( fitness_norm = np.repeat(fitness_norm, len(translated_fitness[0, :])).reshape( len(fitness), len(fitness[0, :]) ) + # Convert zeros to eps to avoid divide by zero. + # Has to be checked! + fitness_norm[fitness_norm == 0] = np.finfo(float).eps normalized_fitness = np.divide(translated_fitness, fitness_norm) # Checked, works. cosine = np.dot(normalized_fitness, np.transpose(vectors.values)) if cosine[np.where(cosine > 1)].size: @@ -53,6 +56,9 @@ def APD_select( assigned_vectors = np.argmax(cosine, axis=1) selection = np.array([], dtype=int) # Selection + # Convert zeros to eps to avoid divide by zero. + # Has to be checked! + refV[refV == 0] = np.finfo(float).eps for i in range(0, len(vectors.values)): sub_population_index = np.atleast_1d( np.squeeze(np.where(assigned_vectors == i)) diff --git a/pyrvea/Selection/tournament_select.py b/pyrvea/Selection/tournament_select.py new file mode 100644 index 0000000..030e062 --- /dev/null +++ b/pyrvea/Selection/tournament_select.py @@ -0,0 +1,26 @@ +import numpy as np + + +def tour_select(fitness, tournament_size): + """Tournament selection. Choose number of individuals to participate + and select the one with the best fitness. + + Parameters + ---------- + fitness : array_like + An array of each individual's fitness. + tournament_size : int + Number of participants in the tournament. + + Returns + ------- + int + The index of the best individual. + """ + aspirants = np.random.choice(len(fitness)-1, tournament_size, replace=False) + chosen = [] + for ind in aspirants: + chosen.append([ind, fitness[ind]]) + chosen.sort(key=lambda x: x[1]) + + return chosen[0][0] diff --git a/requirements.txt b/requirements.txt index a07ed55..ab93961 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,7 @@ docutils==0.14 entrypoints==0.3 flake8==3.7.7 future==0.17.1 +graphviz==0.11.1 idna==2.8 imagesize==1.1.0 ipython-genutils==0.2.0 diff --git a/trend b/trend new file mode 100644 index 0000000..930db53 --- /dev/null +++ b/trend @@ -0,0 +1,255 @@ + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 1.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.75000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.25000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.75000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.25000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.60000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 0.80000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 1.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.30000 + 0.30000 + 0.30000 + 0.30000 + 0.30000 + 0.30000 + 0.30000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.10000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.00000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000 + 0.50000