├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── dist ├── neataptic.js └── worker.js ├── docs ├── 404.html ├── articles │ ├── agario │ │ └── index.html │ ├── classifycolors │ │ └── index.html │ ├── index.html │ ├── neuroevolution │ │ └── index.html │ ├── playground │ │ └── index.html │ └── targetseeking │ │ └── index.html ├── cdn │ ├── 1.2.10 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.11 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.12 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.13 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.14 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.15 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.16 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.17 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.18 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.19 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.20 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.21 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.22 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.23 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.24 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.25 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.26 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.27 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.28 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.29 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.30 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.31 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.32 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.33 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.34 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.0 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.1 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.2 │ │ └── neataptic.js │ ├── 1.3.3 │ │ └── neataptic.js │ ├── 1.3.4 │ │ └── neataptic.js │ ├── 1.3.5 │ │ └── neataptic.js │ ├── 1.3.6 │ │ └── neataptic.js │ ├── 1.3.7 │ │ └── neataptic.js │ ├── 1.3.8 │ │ └── neataptic.js │ ├── 1.3.9 │ │ └── neataptic.js │ ├── 1.4.0 │ │ └── neataptic.js │ ├── 1.4.1 │ │ └── neataptic.js │ ├── 1.4.2 │ │ └── neataptic.js │ ├── 1.4.3 │ │ └── neataptic.js │ ├── 1.4.4 │ │ └── neataptic.js │ ├── 1.4.5 │ │ └── neataptic.js │ ├── 1.4.6 │ │ └── neataptic.js │ └── 1.4.7 │ │ └── neataptic.js ├── css │ ├── base.css │ ├── bootstrap-custom.min.css │ ├── font-awesome-4.5.0.css │ └── highlight.css ├── custom.css ├── docs │ ├── architecture │ │ ├── architecture │ │ │ └── index.html │ │ ├── connection │ │ │ └── index.html │ │ ├── construct │ │ │ └── index.html │ │ ├── group │ │ │ └── index.html │ │ ├── layer │ │ │ └── index.html │ │ ├── network │ │ │ └── index.html │ │ └── node │ │ │ └── index.html │ ├── builtins │ │ ├── builtins │ │ │ └── index.html │ │ ├── gru │ │ │ └── index.html │ │ ├── hopfield │ │ │ └── index.html │ │ ├── lstm │ │ │ └── index.html │ │ ├── narx │ │ │ └── index.html │ │ ├── perceptron │ │ │ └── index.html │ │ └── random │ │ │ └── index.html │ ├── important │ │ ├── evolve │ │ │ └── index.html │ │ ├── important │ │ │ └── index.html │ │ └── train │ │ │ └── index.html │ ├── index.html │ ├── methods │ │ ├── activation │ │ │ └── index.html │ │ ├── cost │ │ │ └── index.html │ │ ├── gating │ │ │ └── index.html │ │ ├── methods │ │ │ └── index.html │ │ ├── mutation │ │ │ └── index.html │ │ ├── rate │ │ │ └── index.html │ │ ├── regularization │ │ │ └── index.html │ │ └── selection │ │ │ └── index.html │ ├── neat │ │ └── index.html │ └── tutorials │ │ ├── evolution │ │ └── index.html │ │ ├── normalization │ │ └── index.html │ │ ├── training │ │ └── index.html │ │ ├── tutorials │ │ └── index.html │ │ └── visualization │ │ └── index.html ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── img │ ├── favicon.ico │ └── grid.png ├── index.html ├── js │ ├── articles │ │ ├── agar.ioai │ │ │ ├── field.js │ │ │ ├── food.js │ │ │ ├── import.js │ │ │ ├── main.js │ │ │ ├── player.js │ │ │ └── population.js │ │ ├── classifycolors │ │ │ ├── custom.css │ │ │ ├── events.js │ │ │ ├── import.js │ │ │ ├── neural.js │ │ │ └── randomColor.js │ │ ├── neuroevolution │ │ │ ├── events.js │ │ │ ├── graph.css │ │ │ ├── graph.js │ │ │ ├── import.js │ │ │ ├── neural.js │ │ │ └── webcola.js │ │ ├── playground │ │ │ ├── events.js │ │ │ ├── extra.css │ │ │ ├── graph.js │ │ │ ├── import.js │ │ │ └── neural.js │ │ └── target-seekingai │ │ │ ├── field.js │ │ │ ├── graph.js │ │ │ ├── import.js │ │ │ ├── main.js │ │ │ ├── player.js │ │ │ ├── population.js │ │ │ └── walker.js │ ├── base.js │ ├── bootstrap-3.0.3.min.js │ ├── highlight.pack.js │ └── jquery-1.10.2.min.js ├── mkdocs │ ├── js │ │ ├── lunr.min.js │ │ ├── mustache.min.js │ │ ├── require.js │ │ ├── search-results-template.mustache │ │ ├── search.js │ │ └── text.js │ └── search_index.json └── sitemap.xml ├── graph ├── README.md ├── graph.css └── graph.js ├── mkdocs ├── mkdocs.yml ├── templates │ ├── articles │ │ ├── agario.md │ │ ├── classifycolors.md │ │ ├── index.md │ │ ├── neuroevolution.md │ │ ├── playground.md │ │ └── targetseeking.md │ ├── docs │ │ ├── NEAT.md │ │ ├── architecture │ │ │ ├── architecture.md │ │ │ ├── connection.md │ │ │ ├── construct.md │ │ │ ├── group.md │ │ │ ├── layer.md │ │ │ ├── network.md │ │ │ └── node.md │ │ ├── builtins │ │ │ ├── builtins.md │ │ │ ├── gru.md │ │ │ ├── hopfield.md │ │ │ ├── lstm.md │ │ │ ├── narx.md │ │ │ ├── perceptron.md │ │ │ └── random.md │ │ ├── important │ │ │ ├── evolve.md │ │ │ ├── important.md │ │ │ └── train.md │ │ ├── index.md │ │ ├── methods │ │ │ ├── activation.md │ │ │ ├── cost.md │ │ │ ├── gating.md │ │ │ ├── methods.md │ │ │ ├── mutation.md │ │ │ ├── rate.md │ │ │ ├── regularization.md │ │ │ └── selection.md │ │ └── tutorials │ │ │ ├── evolution.md │ │ │ ├── normalization.md │ │ │ ├── training.md │ │ │ ├── tutorials.md │ │ │ └── visualization.md │ └── index.md └── theme │ ├── 404.html │ ├── cdn │ ├── 1.2.10 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.11 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.12 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.13 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.14 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.15 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.16 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.17 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.18 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.19 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.20 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.21 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.22 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.23 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.24 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.25 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.26 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.27 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.28 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.29 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.30 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.31 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.32 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.33 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.2.34 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.0 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.1 │ │ ├── neataptic.js │ │ └── neataptic.min.js │ ├── 1.3.2 │ │ └── neataptic.js │ ├── 1.3.3 │ │ └── neataptic.js │ ├── 1.3.4 │ │ └── neataptic.js │ ├── 1.3.5 │ │ └── neataptic.js │ ├── 1.3.6 │ │ └── neataptic.js │ ├── 1.3.7 │ │ └── neataptic.js │ ├── 1.3.8 │ │ └── neataptic.js │ ├── 1.3.9 │ │ └── neataptic.js │ ├── 1.4.0 │ │ └── neataptic.js │ ├── 1.4.1 │ │ └── neataptic.js │ ├── 1.4.2 │ │ └── neataptic.js │ ├── 1.4.3 │ │ └── neataptic.js │ ├── 1.4.4 │ │ └── neataptic.js │ ├── 1.4.5 │ │ └── neataptic.js │ ├── 1.4.6 │ │ └── neataptic.js │ └── 1.4.7 │ │ └── neataptic.js │ ├── custom.css │ ├── js │ └── articles │ │ ├── agar.ioai │ │ ├── field.js │ │ ├── food.js │ │ ├── import.js │ │ ├── main.js │ │ ├── player.js │ │ └── population.js │ │ ├── classifycolors │ │ ├── custom.css │ │ ├── events.js │ │ ├── import.js │ │ ├── neural.js │ │ └── randomColor.js │ │ ├── neuroevolution │ │ ├── events.js │ │ ├── graph.css │ │ ├── graph.js │ │ ├── import.js │ │ ├── neural.js │ │ └── webcola.js │ │ ├── playground │ │ ├── events.js │ │ ├── extra.css │ │ ├── graph.js │ │ ├── import.js │ │ └── neural.js │ │ └── target-seekingai │ │ ├── field.js │ │ ├── graph.js │ │ ├── import.js │ │ ├── main.js │ │ ├── player.js │ │ ├── population.js │ │ └── walker.js │ └── main.html ├── package.json ├── src ├── architecture │ ├── architect.js │ ├── connection.js │ ├── group.js │ ├── layer.js │ ├── network.js │ └── node.js ├── config.js ├── methods │ ├── activation.js │ ├── connection.js │ ├── cost.js │ ├── crossover.js │ ├── gating.js │ ├── methods.js │ ├── mutation.js │ ├── rate.js │ └── selection.js ├── multithreading │ ├── multi.js │ └── workers │ │ ├── browser │ │ └── testworker.js │ │ ├── node │ │ ├── testworker.js │ │ └── worker.js │ │ └── workers.js ├── neat.js └── neataptic.js ├── test ├── dist.js ├── neat.js ├── network.js └── src.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Debug 2 | debug 3 | 4 | # Development files 5 | node_modules 6 | npm-debug.log 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | script: "npm run test:travis" 3 | node_js: 4 | - "node" 5 | - "7.6" 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Thank you for considering contributing to Neataptic! Neataptic is currently only 4 | maintained by a single developer, so every little bit counts! There are many ways 5 | you can contribute: updating the documentation, reporting a bug or creating a new 6 | feature. We also stimulate the creation of projects using Neataptic; this allows us 7 | to show how Neataptic can be used. 8 | 9 | ## Setting up the dev environment 10 | Setting up the developer environment is fairly easy: 11 | 1. Fork the repository (button on the topright corner of this page) 12 | 2. Clone the repository to your computer (clone from chrome [here](https://github.com/wagenaartje/neataptic)) 13 | 3. `cd` into the project directory, and run `npm install` 14 | 15 | And you are good to go! 16 | 17 | **PS**: we use the [Javascript Semistandard Style](https://github.com/Flet/semistandard)! 18 | 19 | ## Bugs 20 | Nobody likes them, and we understand that you want to get rid of them as soon as 21 | possible, but to assure that the debugging proces runs smoothly we need to have 22 | all the information possible about the bug. 23 | 24 | #### Reporting a bug 25 | We need a couple of things to process a bug report efficiently: 26 | 1. The version (1.x.x) 27 | 2. The error log (this allows us to trace the source of the bug) 28 | 3. What you were trying to do (e.g. connecting a node to a node) 29 | 4. (_if possible_) a piece of code that allows us to reproduce the bug 30 | 5. (_optionally_) Operating system and browser 31 | 32 | #### Fixing a bug 33 | When you encounter a bug and want to fix it, _create an issue first_. Then clearly 34 | say that you will create a pull request yourself that fixes the bug. This makes sure 35 | people are aware that the bug exists. 36 | 37 | What you have to provide in your pull request: 38 | 1. A link to the issue that describes the bug 39 | 2. (_if not in the issue yet_), a brief explanation of what was going wrong 40 | 3. How you fixed it 41 | 4. What the possible side-effects are of the code change 42 | 43 | And the pull request will be merged in no-time! 44 | 45 | ## Features 46 | Neataptic gets extended all the time! However we prefer qualitative over quantitative 47 | features - anyone can add a new `Activation` method for example, but you have to ask 48 | yourself if it really improves the project. But _always_ feel free to create a pull 49 | request with new features, as long as you incorporate the following: 50 | 1. What feature you are adding (/improving) 51 | 2. A usage example of the new feature (in code!) 52 | 3. Why you think it adds something to Neataptic 53 | 4. Possible side-effects of the new feature 54 | 55 | Afterwards, there will be quick response - but the pull request may take some time to 56 | be accepted, so we can give other contributors time to comment as well. 57 | 58 | PS: If you want to make big improvements/features, please create an issue or send 59 | an e-mail to wagenaartje@protonmail.com 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2017 Thomas Wagenaar . Copyright for 4 | portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a 5 | part of project Synaptic. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE 24 | -------------------------------------------------------------------------------- /dist/worker.js: -------------------------------------------------------------------------------- 1 | var { multi, methods } = require('../../../neataptic'); 2 | 3 | var set = []; 4 | var cost; 5 | var F = multi.activations; 6 | 7 | process.on('message', function (e) { 8 | if (typeof e.set === 'undefined') { 9 | var A = e.activations; 10 | var S = e.states; 11 | var data = e.conns; 12 | 13 | var result = multi.testSerializedSet(set, cost, A, S, data, F); 14 | 15 | process.send(result); 16 | } else { 17 | cost = methods.cost[e.cost]; 18 | set = multi.deserializeDataSet(e.set); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Neataptic.js - 404 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 62 | 63 |
64 |
65 | 66 |
67 |

404: Page not found

68 |

If something is wrong, please create an issue here!

69 |
70 |
71 |
72 | 73 | 74 | 86 | -------------------------------------------------------------------------------- /docs/css/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | This is the GitHub theme for highlight.js 3 | 4 | github.com style (c) Vasily Polovnyov 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; 10 | overflow-x: auto; 11 | color: #333; 12 | -webkit-text-size-adjust: none; 13 | } 14 | 15 | .hljs-comment, 16 | .diff .hljs-header, 17 | .hljs-javadoc { 18 | color: #998; 19 | font-style: italic; 20 | } 21 | 22 | .hljs-keyword, 23 | .css .rule .hljs-keyword, 24 | .hljs-winutils, 25 | .nginx .hljs-title, 26 | .hljs-subst, 27 | .hljs-request, 28 | .hljs-status { 29 | color: #333; 30 | font-weight: bold; 31 | } 32 | 33 | .hljs-number, 34 | .hljs-hexcolor, 35 | .ruby .hljs-constant { 36 | color: #008080; 37 | } 38 | 39 | .hljs-string, 40 | .hljs-tag .hljs-value, 41 | .hljs-phpdoc, 42 | .hljs-dartdoc, 43 | .tex .hljs-formula { 44 | color: #d14; 45 | } 46 | 47 | .hljs-title, 48 | .hljs-id, 49 | .scss .hljs-preprocessor { 50 | color: #900; 51 | font-weight: bold; 52 | } 53 | 54 | .hljs-list .hljs-keyword, 55 | .hljs-subst { 56 | font-weight: normal; 57 | } 58 | 59 | .hljs-class .hljs-title, 60 | .hljs-type, 61 | .vhdl .hljs-literal, 62 | .tex .hljs-command { 63 | color: #458; 64 | font-weight: bold; 65 | } 66 | 67 | .hljs-tag, 68 | .hljs-tag .hljs-title, 69 | .hljs-rule .hljs-property, 70 | .django .hljs-tag .hljs-keyword { 71 | color: #000080; 72 | font-weight: normal; 73 | } 74 | 75 | .hljs-attribute, 76 | .hljs-variable, 77 | .lisp .hljs-body, 78 | .hljs-name { 79 | color: #008080; 80 | } 81 | 82 | .hljs-regexp { 83 | color: #009926; 84 | } 85 | 86 | .hljs-symbol, 87 | .ruby .hljs-symbol .hljs-string, 88 | .lisp .hljs-keyword, 89 | .clojure .hljs-keyword, 90 | .scheme .hljs-keyword, 91 | .tex .hljs-special, 92 | .hljs-prompt { 93 | color: #990073; 94 | } 95 | 96 | .hljs-built_in { 97 | color: #0086b3; 98 | } 99 | 100 | .hljs-preprocessor, 101 | .hljs-pragma, 102 | .hljs-pi, 103 | .hljs-doctype, 104 | .hljs-shebang, 105 | .hljs-cdata { 106 | color: #999; 107 | font-weight: bold; 108 | } 109 | 110 | .hljs-deletion { 111 | background: #fdd; 112 | } 113 | 114 | .hljs-addition { 115 | background: #dfd; 116 | } 117 | 118 | .diff .hljs-change { 119 | background: #0086b3; 120 | } 121 | 122 | .hljs-chunk { 123 | color: #aaa; 124 | } 125 | -------------------------------------------------------------------------------- /docs/custom.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | font-family: 'Roboto', sans-serif; 7 | font-size: 150%; 8 | } 9 | .brand{ 10 | color: white; 11 | font-size: 20px; 12 | font-weight: 500; 13 | letter-spacing: 1px; 14 | } 15 | .nav > ul> li { 16 | list-style-type: none; 17 | } 18 | .nav > ul> li > a { 19 | text-decoration: none; 20 | } 21 | /* navbar */ 22 | .navbar-default { 23 | background-color: #2C3963; 24 | border-bottom: 2px solid white; 25 | } 26 | /* Title */ 27 | .navbar-default .navbar-brand { 28 | color: white; 29 | } 30 | .navbar-default .navbar-brand:hover, 31 | .navbar-default .navbar-brand:focus { 32 | color: #5E5E5E; 33 | } 34 | /* Link */ 35 | .navbar-default .navbar-nav > li > a { 36 | color: rgba(255,255,255,.8); 37 | } 38 | .navbar-default .navbar-nav > li > a:hover, 39 | .navbar-default .navbar-nav > li > a:focus { 40 | color: white; 41 | } 42 | .navbar-default .navbar-nav > .active > a, 43 | .navbar-default .navbar-nav > .active > a:hover, 44 | .navbar-default .navbar-nav > .active > a:focus { 45 | color: white; 46 | background-color: #2C3963; 47 | border-bottom: 2px solid white; 48 | } 49 | 50 | /* Custom coloring */ 51 | .btn-primary{ 52 | background-color: #2C3963; 53 | border-color: #2F3D68; 54 | } 55 | 56 | .panel-warning > .panel-heading{ 57 | background-color: #2C3963; 58 | border-color: #2C3963; 59 | color: white; 60 | } 61 | .panel-warning{ 62 | border-color: #2C3963; 63 | } 64 | 65 | /* Homepage */ 66 | .jumbotron.vertical-center { 67 | margin-bottom: 0; /* Remove the default bottom margin of .jumbotron */ 68 | background-color: #2C3963; 69 | } 70 | .vertical-center { 71 | min-height: 100%; /* Fallback for vh unit */ 72 | min-height: 100vh; /* You might also want to use 73 | 'height' property instead. 74 | 75 | Note that for percentage values of 76 | 'height' or 'min-height' properties, 77 | the 'height' of the parent element 78 | should be specified explicitly. 79 | 80 | In this case the parent of '.vertical-center' 81 | is the element */ 82 | 83 | /* Make it a flex container */ 84 | display: -webkit-box; 85 | display: -moz-box; 86 | display: -ms-flexbox; 87 | display: -webkit-flex; 88 | display: flex; 89 | 90 | /* Align the bootstrap's container vertically */ 91 | -webkit-box-align : center; 92 | -webkit-align-items : center; 93 | -moz-box-align : center; 94 | -ms-flex-align : center; 95 | align-items : center; 96 | 97 | /* In legacy web browsers such as Firefox 9 98 | we need to specify the width of the flex container */ 99 | width: 100%; 100 | 101 | /* Also 'margin: 0 auto' doesn't have any effect on flex items in such web browsers 102 | hence the bootstrap's container won't be aligned to the center anymore. 103 | 104 | Therefore, we should use the following declarations to get it centered again */ 105 | -webkit-box-pack : center; 106 | -moz-box-pack : center; 107 | -ms-flex-pack : center; 108 | -webkit-justify-content : center; 109 | justify-content : center; 110 | } 111 | .welcome { 112 | color: white; 113 | } 114 | .subtitle { 115 | padding: 0; 116 | margin: 0; 117 | } 118 | -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/docs/img/grid.png -------------------------------------------------------------------------------- /docs/js/articles/agar.ioai/field.js: -------------------------------------------------------------------------------- 1 | /* Global vars */ 2 | var players = []; 3 | var foods = []; 4 | var iteration = 0; 5 | var highestScore = 0; 6 | 7 | /** Setup the canvas */ 8 | function setup(){ 9 | var canvas = createCanvas(WIDTH, HEIGHT); 10 | canvas.parent('field'); 11 | initNeat(); 12 | 13 | // Create some food 14 | for(var i = 0; i < FOOD_AMOUNT; i++){ 15 | new Food(); 16 | } 17 | 18 | startEvaluation(); 19 | } 20 | 21 | function draw(){ 22 | clear(); 23 | squareGrid(); 24 | 25 | // Check if evaluation is done 26 | if(iteration == ITERATIONS){ 27 | endEvaluation(); 28 | iteration = 0; 29 | } 30 | 31 | // Update and visualise players 32 | for(var i = players.length - 1; i >= 0; i--){ 33 | var player = players[i]; 34 | 35 | // Some players are eaten during the iteration 36 | player.update(); 37 | player.show(); 38 | } 39 | 40 | // Update and visualise food 41 | for(var i = foods.length - 1; i >= 0; i--){ 42 | foods[i].show(); 43 | } 44 | 45 | iteration++; 46 | } 47 | 48 | /** Draw a square grid with grey lines */ 49 | function squareGrid(){ 50 | stroke(204, 204, 204, 160); 51 | fill(255); 52 | for(var x = 0; x < WIDTH/40; x++){ 53 | line(x * 40, 0, x * 40, HEIGHT); 54 | } 55 | for(var y = 0; y < HEIGHT/40; y++){ 56 | line(0, y * 40, WIDTH, y * 40); 57 | } 58 | noStroke(); 59 | } 60 | 61 | /** Calculate distance between two points */ 62 | function distance(x1, y1, x2, y2){ 63 | var dx = x1 - x2; 64 | var dy = y1 - y2; 65 | 66 | return Math.sqrt(dx * dx + dy * dy); 67 | } 68 | 69 | /** Get a relative color between red and green */ 70 | var activationColor = function(value, max){ 71 | var power = 1 - Math.min(value/max, 1); 72 | var color = [255, 255, 0] 73 | 74 | if(power < 0.5){ 75 | color[0] = 2 * power * 255; 76 | } else { 77 | color[1] = (1.0 - 2 * (power - 0.5)) * 255; 78 | } 79 | 80 | return color; 81 | } 82 | 83 | /** Get the angle from one point to another */ 84 | function angleToPoint(x1, y1, x2, y2){ 85 | d = distance(x1, y1, x2, y2); 86 | dx = (x2-x1) / d; 87 | dy = (y2-y1) / d; 88 | 89 | a = Math.acos(dx); 90 | a = dy < 0 ? 2 * Math.PI - a : a; 91 | return a; 92 | } 93 | -------------------------------------------------------------------------------- /docs/js/articles/agar.ioai/food.js: -------------------------------------------------------------------------------- 1 | function Food(){ 2 | this.x = Math.floor(Math.random() * WIDTH); 3 | this.y = Math.floor(Math.random() * HEIGHT); 4 | this.area = FOOD_AREA; 5 | 6 | this.color = [ 7 | Math.round(Math.random() * 255), 8 | Math.round(Math.random() * 255), 9 | Math.round(Math.random() * 255) 10 | ]; 11 | 12 | foods.push(this); 13 | } 14 | 15 | Food.prototype = { 16 | /** Display the player on the field */ 17 | show: function(){ 18 | var radius = Math.sqrt(this.area / PI); 19 | 20 | fill(this.color[0], this.color[1], this.color[2]); 21 | noStroke(); 22 | ellipse(this.x, this.y, radius); 23 | }, 24 | 25 | /** Restart from new position */ 26 | restart: function(){ 27 | this.x = Math.floor(Math.random() * WIDTH); 28 | this.y = Math.floor(Math.random() * HEIGHT); 29 | }, 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /docs/js/articles/agar.ioai/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"}, 4 | { type: 'script', url: "../../js/articles/agar.ioai/main.js"}, 5 | { type: 'script', url: "../../js/articles/agar.ioai/population.js"}, 6 | { type: 'script', url: "../../js/articles/agar.ioai/player.js"}, 7 | { type: 'script', url: "../../js/articles/agar.ioai/food.js"}, 8 | { type: 'script', url: "../../js/articles/agar.ioai/field.js"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.rel = 'stylesheet'; 23 | stylesheet.type = 'text/css'; 24 | stylesheet.href = link.url; 25 | stylesheet.media = "screen,print"; 26 | document.head.appendChild(stylesheet); 27 | } 28 | }); 29 | } 30 | loadScript(list.shift()).then(function() { 31 | if (list.length > 0) { 32 | require(list); 33 | } 34 | }) 35 | } 36 | 37 | require(scripts); 38 | -------------------------------------------------------------------------------- /docs/js/articles/agar.ioai/main.js: -------------------------------------------------------------------------------- 1 | /** Rename vars */ 2 | var Neat = neataptic.Neat; 3 | var Methods = neataptic.Methods; 4 | var Config = neataptic.Config; 5 | var Architect = neataptic.Architect; 6 | 7 | /** Turn off warnings */ 8 | Config.warnings = false; 9 | 10 | /** Settings */ 11 | var WIDTH = $('#field').width(); 12 | var HEIGHT = 500; 13 | 14 | var MAX_AREA = 10000; 15 | var MIN_AREA = 400; 16 | 17 | var RELATIVE_SIZE = 1.1; 18 | var DECREASE_SIZE = 0.998; 19 | 20 | var DETECTION_RADIUS = 150; 21 | var FOOD_DETECTION = 3; 22 | var PLAYER_DETECTION = 3; 23 | 24 | var MIN_SPEED = 0.6; 25 | var SPEED = 2; 26 | 27 | var FOOD_AREA = 80; 28 | var FOOD_AMOUNT = Math.round(WIDTH * HEIGHT * 4e-4); 29 | 30 | // GA settings 31 | var PLAYER_AMOUNT = Math.round(WIDTH * HEIGHT * 8e-5); 32 | var ITERATIONS = 10e10; 33 | var START_HIDDEN_SIZE = 0; 34 | 35 | // Trained population 36 | var USE_TRAINED_POP = true; 37 | 38 | // Global vars 39 | var neat; 40 | 41 | /** Construct the genetic algorithm */ 42 | function initNeat(){ 43 | neat = new Neat( 44 | 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, 45 | 2, 46 | null, 47 | { 48 | mutation: [ 49 | Methods.Mutation.ADD_NODE, 50 | Methods.Mutation.SUB_NODE, 51 | Methods.Mutation.ADD_CONN, 52 | Methods.Mutation.SUB_CONN, 53 | Methods.Mutation.MOD_WEIGHT, 54 | Methods.Mutation.MOD_BIAS, 55 | Methods.Mutation.MOD_ACTIVATION, 56 | Methods.Mutation.ADD_GATE, 57 | Methods.Mutation.SUB_GATE, 58 | Methods.Mutation.ADD_SELF_CONN, 59 | Methods.Mutation.SUB_SELF_CONN, 60 | Methods.Mutation.ADD_BACK_CONN, 61 | Methods.Mutation.SUB_BACK_CONN 62 | ], 63 | popsize: PLAYER_AMOUNT, 64 | mutationRate: 0.3, 65 | elitism: Math.round(0.1 * PLAYER_AMOUNT), 66 | network: new Architect.Random( 67 | 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, 68 | START_HIDDEN_SIZE, 69 | 2 70 | ) 71 | } 72 | ); 73 | 74 | if(USE_TRAINED_POP){ 75 | neat.population = population; 76 | } 77 | } 78 | 79 | /** Start the evaluation of the current generation */ 80 | function startEvaluation(){ 81 | players = []; 82 | highestScore = 0; 83 | 84 | for(var genome in neat.population){ 85 | genome = neat.population[genome]; 86 | new Player(genome); 87 | } 88 | } 89 | 90 | /** End the evaluation of the current generation */ 91 | function endEvaluation(){ 92 | console.log('Generation:', neat.generation, '- average score:', neat.getAverage()); 93 | 94 | neat.sort(); 95 | var newPopulation = []; 96 | 97 | // Elitism 98 | for(var i = 0; i < neat.elitism; i++){ 99 | newPopulation.push(neat.population[i]); 100 | } 101 | 102 | // Breed the next individuals 103 | for(var i = 0; i < neat.popsize - neat.elitism; i++){ 104 | newPopulation.push(neat.getOffspring()); 105 | } 106 | 107 | // Replace the old population with the new population 108 | neat.population = newPopulation; 109 | neat.mutate(); 110 | 111 | neat.generation++; 112 | startEvaluation(); 113 | } 114 | -------------------------------------------------------------------------------- /docs/js/articles/classifycolors/custom.css: -------------------------------------------------------------------------------- 1 | #circle { 2 | width: 20px; 3 | height: 20px; 4 | -webkit-border-radius: 10px; 5 | -moz-border-radius: 10px; 6 | border-radius: 10px; 7 | display: inline-block; 8 | } 9 | -------------------------------------------------------------------------------- /docs/js/articles/classifycolors/events.js: -------------------------------------------------------------------------------- 1 | $('.colors').change(function(){ 2 | var color = $(this).attr('value'); 3 | if($(this).is(":checked")) { 4 | COLORS.push(color); 5 | } else { 6 | COLORS.splice(COLORS.indexOf(color), 1); 7 | } 8 | 9 | set = createSet(); 10 | visualiseSet(); 11 | }); 12 | $('.start').click(function(e){ 13 | e.preventDefault(); 14 | if(running == false){ 15 | running = true; 16 | iteration = 0; 17 | createNeat(); 18 | $(this).html(' Stop evolution'); 19 | setTimeout(loop, 1); 20 | } else { 21 | running = false; 22 | $(this).html(' Start evolution'); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /docs/js/articles/classifycolors/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js" }, 3 | { type: 'script', url: "../../js/articles/classifycolors/events.js" }, 4 | { type: 'script', url: "../../js/articles/classifycolors/randomColor.js" }, 5 | { type: 'script', url: "../../js/articles/classifycolors/neural.js" }, 6 | { type: 'css', url: "../../js/articles/classifycolors/custom.css"} 7 | ]; 8 | 9 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 10 | function require(list) { 11 | function loadScript(link) { 12 | return new Promise(function(fulfill, reject) { 13 | if(link.type == 'script'){ 14 | var script = document.createElement("script"); 15 | script.addEventListener("load", fulfill); 16 | script.src = link.url; 17 | document.head.appendChild(script); 18 | } else if(link.type == 'css'){ 19 | var stylesheet = document.createElement('link'); 20 | stylesheet.rel = 'stylesheet'; 21 | stylesheet.type = 'text/css'; 22 | stylesheet.href = link.url; 23 | stylesheet.media = "screen,print"; 24 | document.head.appendChild(stylesheet); 25 | } 26 | }); 27 | } 28 | loadScript(list.shift()).then(function() { 29 | if (list.length > 0) { 30 | require(list); 31 | } 32 | }) 33 | } 34 | 35 | require(scripts); 36 | -------------------------------------------------------------------------------- /docs/js/articles/classifycolors/neural.js: -------------------------------------------------------------------------------- 1 | var Neat = neataptic.Neat; 2 | var Methods = neataptic.Methods; 3 | var Network = neataptic.Network; 4 | 5 | var set; 6 | var neat; 7 | var running = false; 8 | var iteration = 0; 9 | 10 | var PER_COLOR = 50; 11 | // Possible colors: red, orange, yellow, green, blue, purple, pink and monochrome 12 | var COLORS = ['red', 'green', 'blue']; 13 | var network; 14 | 15 | $( document ).ready(function(){ 16 | set = createSet(); 17 | visualiseSet(); 18 | }); 19 | 20 | function createNeat(){ 21 | network = new Network(3, COLORS.length); 22 | /*neat = new Neat(3, COLORS.length, fitness, { 23 | mutation: [ 24 | Methods.Mutation.ADD_NODE, 25 | Methods.Mutation.ADD_CONN, 26 | Methods.Mutation.MOD_WEIGHT, 27 | Methods.Mutation.MOD_BIAS, 28 | Methods.Mutation.SUB_NODE, 29 | Methods.Mutation.MOD_ACTIVATION 30 | ], 31 | mutationRate: 0.6, 32 | elitism: 5, 33 | popsize: 100, 34 | });*/ 35 | } 36 | 37 | function visualiseSet(){ 38 | $('.set').empty(); 39 | for(color in COLORS){ 40 | $('.set').append('

' + COLORS[color] + '

'); 41 | } 42 | 43 | for(var item in set){ 44 | item = set[item]; 45 | $('.'+ item.color).append('
'); 46 | } 47 | } 48 | 49 | function visualiseGenomeSet(genome){ 50 | $('.fittestset').empty(); 51 | for(color in COLORS){ 52 | $('.fittestset').append('

' + COLORS[color] + '

'); 53 | } 54 | 55 | for(var item in set){ 56 | item = set[item]; 57 | var output = genome.activate(item.input); 58 | var max = Math.max.apply(null, output); 59 | var color = COLORS[output.indexOf(max)]; 60 | 61 | $('.fittest'+ color).append('
'); 62 | } 63 | } 64 | 65 | function loop(){ 66 | network.evolve(set, { 67 | iterations: 1, 68 | mutationRate: 0.6, 69 | elisitm: 5, 70 | popSize: 100, 71 | mutation: Methods.Mutation.FFW, 72 | cost: Methods.Cost.MSE 73 | }); 74 | 75 | visualiseGenomeSet(network); 76 | 77 | $('.iteration').text(iteration); 78 | $('.bestfitness').text(network.test(set).error); 79 | 80 | iteration++; 81 | if(running) setTimeout(loop, 1); 82 | } 83 | 84 | // Thanks to https://github.com/davidmerfield/randomColor !! 85 | function createSet(){ 86 | var set = []; 87 | 88 | for(index in COLORS){ 89 | var color = COLORS[index]; 90 | 91 | var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'}); 92 | 93 | for(var random in randomColors){ 94 | var rgb = randomColors[random]; 95 | random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(','); 96 | for(var y in random) random[y] = random[y]/255; 97 | 98 | var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0); 99 | output[index] = 1; 100 | 101 | set.push({ input: random, output: output, color: color, rgb: rgb}); 102 | } 103 | } 104 | 105 | return set; 106 | } 107 | -------------------------------------------------------------------------------- /docs/js/articles/neuroevolution/events.js: -------------------------------------------------------------------------------- 1 | $(document).on('click', '.panel div.clickable', function (e) { 2 | var $this = $(this); //Heading 3 | var $panel = $this.parent('.panel'); 4 | var $panel_body = $panel.children('.panel-body'); 5 | var $display = $panel_body.css('display'); 6 | 7 | if ($display == 'block') { 8 | $panel_body.slideUp(); 9 | } else if($display == 'none') { 10 | $panel_body.slideDown(); 11 | } 12 | }); 13 | 14 | $(document).ready(function(e){ 15 | var $classy = '.panel.autocollapse'; 16 | 17 | var $found = $($classy); 18 | $found.find('.panel-body').hide(); 19 | $found.removeClass($classy); 20 | }); 21 | -------------------------------------------------------------------------------- /docs/js/articles/neuroevolution/graph.css: -------------------------------------------------------------------------------- 1 | .node { 2 | cursor: move; 3 | stroke-width: 1.5px; 4 | } 5 | .link { 6 | fill: none; 7 | stroke: #BDBDBD; 8 | stroke-width: 1.5px; 9 | opacity: 0.4; 10 | marker-end: url(#end-arrow); 11 | } 12 | .label { 13 | fill: #CCCCCC; 14 | font-size: 9px; 15 | text-anchor: middle; 16 | cursor: move; 17 | font-family: Arial; 18 | } 19 | #end-arrow{ 20 | opacity: 0.4; 21 | } 22 | .INPUT{ 23 | fill: #ff6666; 24 | stroke: #ff4d4d; 25 | } 26 | .OUTPUT{ 27 | fill : #ff8c66; 28 | stroke: #ff794d; 29 | } 30 | .LOGISTIC{ 31 | fill: #ffb366; 32 | stroke: #ffa64d; 33 | } 34 | .TANH{ 35 | fill: #ffd966; 36 | stroke: #ffd24d; 37 | } 38 | .IDENTITY{ 39 | fill: #ffff66; 40 | stroke: #ffff4d; 41 | } 42 | .STEP{ 43 | fill: #d9ff66; 44 | stroke: #d2ff4d; 45 | } 46 | .RELU{ 47 | fill: #b3ff66; 48 | stroke: #a6ff4d; 49 | } 50 | .SOFTSIGN{ 51 | fill: #8cff66; 52 | stroke: #79ff4d; 53 | } 54 | .SINUSOID{ 55 | fill: #66ff66; 56 | stroke: #4dff4d; 57 | } 58 | .GAUSSIAN{ 59 | fill: #66ff8c; 60 | stroke: #4dff79; 61 | } 62 | .BENT_IDENTITY{ 63 | fill: #66ffd9; 64 | stroke: #4dffd2; 65 | } 66 | .BIPOLAR{ 67 | fill: #66d9ff; 68 | stroke: #4dd2ff; 69 | } 70 | .BIPOLAR_SIGMOID{ 71 | fill: #66b3ff; 72 | stroke: #4da6ff; 73 | } 74 | .HARD_TANH{ 75 | fill: #668cff; 76 | stroke: #4d79ff; 77 | } 78 | .ABSOLUTE{ 79 | fill: #6666ff; 80 | stroke: #4d4dff; 81 | } 82 | .GATE{ 83 | fill: #003300; 84 | stroke: #001a00; 85 | } 86 | .CONSTANT{ 87 | fill: #ff00ff; 88 | stroke: #e600e6; 89 | } 90 | -------------------------------------------------------------------------------- /docs/js/articles/neuroevolution/graph.js: -------------------------------------------------------------------------------- 1 | var NODE_RADIUS = 7; 2 | var REPEL_FORCE = 0; 3 | var LINK_DISTANCE = 100; 4 | 5 | var drawGraph = function(graph, panel, width, height) { 6 | var d3cola = cola.d3adaptor() 7 | .avoidOverlaps(true) 8 | .size([width, height]); 9 | 10 | var svg = d3.select(panel); 11 | 12 | d3.selectAll(panel + "> *").remove(); 13 | 14 | // define arrow markers for graph links 15 | svg.append('svg:defs').append('svg:marker') 16 | .attr('id', 'end-arrow') 17 | .attr('viewBox', '0 -5 10 10') 18 | .attr('refX', 6) 19 | .attr('markerWidth', 4) 20 | .attr('markerHeight', 4) 21 | .attr('orient', 'auto') 22 | .append('svg:path') 23 | .attr('d', 'M0,-5L10,0L0,5') 24 | 25 | graph.nodes.forEach(function (v) { v.height = v.width = 2 * NODE_RADIUS; }); 26 | 27 | d3cola 28 | .nodes(graph.nodes) 29 | .links(graph.links) 30 | //.constraints(graph.constraints) 31 | .symmetricDiffLinkLengths(REPEL_FORCE) 32 | .linkDistance(LINK_DISTANCE) 33 | .start(10, 15, 20); 34 | 35 | var path = svg.selectAll(".link") 36 | .data(graph.links) 37 | .enter().append('svg:path') 38 | .attr('class', 'link') 39 | 40 | path.append("title") 41 | .text(function (d) { 42 | var text = ""; 43 | text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";; 44 | text += "Source: " + d.source.id + "\n";; 45 | text += "Target: " + d.target.id; 46 | return text; 47 | }); 48 | 49 | var node = svg.selectAll(".node") 50 | .data(graph.nodes) 51 | .enter().append("circle") 52 | .attr("class", function(d){ 53 | return "node " + d.name; 54 | }) 55 | .attr("r", function(d) { return NODE_RADIUS; }) 56 | 57 | .call(d3cola.drag); 58 | 59 | node.append("title") 60 | .text(function (d){ 61 | var text = ""; 62 | text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n"; 63 | text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n"; 64 | text += "Position: " + d.id; 65 | return text; 66 | }); 67 | 68 | var label = svg.selectAll(".label") 69 | .data(graph.nodes) 70 | .enter().append("text") 71 | .attr("class", "label") 72 | .text(function (d){return '(' + d.index + ') ' + d.name; }) 73 | .call(d3cola.drag) 74 | 75 | d3cola.on("tick", function () { 76 | // draw directed edges with proper padding from node centers 77 | path.attr('d', function (d) { 78 | var deltaX = d.target.x - d.source.x, 79 | deltaY = d.target.y - d.source.y, 80 | dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), 81 | normX = deltaX / dist, 82 | normY = deltaY / dist; 83 | 84 | if(isNaN(normX)) normX = 0; 85 | if(isNaN(normY)) normY = 0; 86 | 87 | sourcePadding = NODE_RADIUS, 88 | targetPadding = NODE_RADIUS + 2, 89 | sourceX = d.source.x + (sourcePadding * normX), 90 | sourceY = d.source.y + (sourcePadding * normY), 91 | targetX = d.target.x - (targetPadding * normX), 92 | targetY = d.target.y - (targetPadding * normY); 93 | 94 | // Defaults for normal edge. 95 | drx = 0, 96 | dry = 0, 97 | xRotation = 0, // degrees 98 | largeArc = 0, // 1 or 0 99 | sweep = 1; // 1 or 0 100 | 101 | // Self edge. 102 | if (d.source.x === d.target.x && d.source.y === d.target.y) { 103 | drx = dist; 104 | dry = dist; 105 | xRotation = -45; 106 | largeArc = 1; 107 | drx = 20; 108 | dry = 20; 109 | targetX = targetX + 1; 110 | targetY = targetY + 1; 111 | } 112 | return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY; 113 | }); 114 | 115 | node.attr("cx", function (d) { return d.x; }) 116 | .attr("cy", function (d) { return d.y; }) 117 | 118 | label 119 | .attr("x", function (d) { return d.x + 10; }) 120 | .attr("y", function (d) { return d.y - 10; }); 121 | }); 122 | }; 123 | -------------------------------------------------------------------------------- /docs/js/articles/neuroevolution/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"}, 4 | { type: 'script', url: "../../js/articles/neuroevolution/webcola.js"}, 5 | { type: 'script', url: "../../js/articles/neuroevolution/events.js"}, 6 | { type: 'script', url: "../../js/articles/neuroevolution/graph.js"}, 7 | { type: 'script', url: "../../js/articles/neuroevolution/neural.js"}, 8 | { type: 'css', url: "../../js/articles/neuroevolution/graph.css"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.addEventListener("load", fulfill); 23 | stylesheet.rel = 'stylesheet'; 24 | stylesheet.type = 'text/css'; 25 | stylesheet.href = link.url; 26 | stylesheet.media = "screen,print"; 27 | document.head.appendChild(stylesheet); 28 | } 29 | }); 30 | } 31 | loadScript(list.shift()).then(function() { 32 | if (list.length > 0) { 33 | require(list); 34 | } 35 | }) 36 | } 37 | 38 | require(scripts); 39 | -------------------------------------------------------------------------------- /docs/js/articles/playground/events.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() { 2 | $( ".start" ).click(function() { 3 | $( ".start" ).html(' Running...'); 4 | newNeat(); 5 | loop(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /docs/js/articles/playground/extra.css: -------------------------------------------------------------------------------- 1 | .btn-group, .input-group, pre{ 2 | margin-top: 10px; 3 | } 4 | .node { 5 | cursor: move; 6 | stroke-width: 1.5px; 7 | } 8 | .link { 9 | fill: none; 10 | stroke: #BDBDBD; 11 | stroke-width: 1.5px; 12 | opacity: 0.4; 13 | marker-end: url(#end-arrow); 14 | } 15 | .label { 16 | fill: #CCCCCC; 17 | font-size: 9px; 18 | text-anchor: middle; 19 | cursor: move; 20 | font-family: Arial; 21 | } 22 | #end-arrow{ 23 | opacity: 0.4; 24 | } 25 | .INPUT{ 26 | fill: #ff6666; 27 | stroke: #ff4d4d; 28 | } 29 | .OUTPUT{ 30 | fill : #ff8c66; 31 | stroke: #ff794d; 32 | } 33 | .LOGISTIC{ 34 | fill: #ffb366; 35 | stroke: #ffa64d; 36 | } 37 | .TANH{ 38 | fill: #ffd966; 39 | stroke: #ffd24d; 40 | } 41 | .IDENTITY{ 42 | fill: #ffff66; 43 | stroke: #ffff4d; 44 | } 45 | .STEP{ 46 | fill: #d9ff66; 47 | stroke: #d2ff4d; 48 | } 49 | .RELU{ 50 | fill: #b3ff66; 51 | stroke: #a6ff4d; 52 | } 53 | .SOFTSIGN{ 54 | fill: #8cff66; 55 | stroke: #79ff4d; 56 | } 57 | .SINUSOID{ 58 | fill: #66ff66; 59 | stroke: #4dff4d; 60 | } 61 | .GAUSSIAN{ 62 | fill: #66ff8c; 63 | stroke: #4dff79; 64 | } 65 | .BENT_IDENTITY{ 66 | fill: #66ffd9; 67 | stroke: #4dffd2; 68 | } 69 | .BIPOLAR{ 70 | fill: #66d9ff; 71 | stroke: #4dd2ff; 72 | } 73 | .BIPOLAR_SIGMOID{ 74 | fill: #66b3ff; 75 | stroke: #4da6ff; 76 | } 77 | .HARD_TANH{ 78 | fill: #668cff; 79 | stroke: #4d79ff; 80 | } 81 | .ABSOLUTE{ 82 | fill: #6666ff; 83 | stroke: #4d4dff; 84 | } 85 | .GATE{ 86 | fill: #003300; 87 | stroke: #001a00; 88 | } 89 | .CONSTANT{ 90 | fill: #ff00ff; 91 | stroke: #e600e6; 92 | } 93 | -------------------------------------------------------------------------------- /docs/js/articles/playground/graph.js: -------------------------------------------------------------------------------- 1 | var NODE_RADIUS = 7; 2 | var GATE_RADIUS = 2; 3 | var REPEL_FORCE = 0; 4 | var LINK_DISTANCE = 100; 5 | 6 | var WIDTH = 500; 7 | var HEIGHT = 600; 8 | 9 | var d3cola = cola.d3adaptor() 10 | .avoidOverlaps(true) 11 | .size([WIDTH, HEIGHT]); 12 | 13 | var drawGraph = function(graph, panel) { 14 | var svg = d3.select(panel); 15 | 16 | d3.selectAll(panel + "> *").remove(); 17 | 18 | // define arrow markers for graph links 19 | svg.append('svg:defs').append('svg:marker') 20 | .attr('id', 'end-arrow') 21 | .attr('viewBox', '0 -5 10 10') 22 | .attr('refX', 6) 23 | .attr('markerWidth', 4) 24 | .attr('markerHeight', 4) 25 | .attr('orient', 'auto') 26 | .append('svg:path') 27 | .attr('d', 'M0,-5L10,0L0,5') 28 | 29 | graph.nodes.forEach(function(v){ 30 | v.height = v.width = 2 * (v.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS); } 31 | ); 32 | 33 | d3cola 34 | .nodes(graph.nodes) 35 | .links(graph.links) 36 | .constraints(graph.constraints) 37 | .symmetricDiffLinkLengths(REPEL_FORCE) 38 | .linkDistance(LINK_DISTANCE) 39 | .start(10, 15, 20); 40 | 41 | var path = svg.selectAll(".link") 42 | .data(graph.links) 43 | .enter().append('svg:path') 44 | .attr('class', 'link') 45 | 46 | path.append("title") 47 | .text(function (d) { 48 | var text = ""; 49 | text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";; 50 | text += "Source: " + d.source.id + "\n";; 51 | text += "Target: " + d.target.id; 52 | return text; 53 | }); 54 | 55 | var node = svg.selectAll(".node") 56 | .data(graph.nodes) 57 | .enter().append("circle") 58 | .attr("class", function(d){ 59 | return "node " + d.name; 60 | }) 61 | .attr("r", function(d) { return d.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS; }) 62 | 63 | .call(d3cola.drag); 64 | 65 | node.append("title") 66 | .text(function (d){ 67 | var text = ""; 68 | text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n"; 69 | text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n"; 70 | text += "Position: " + d.id; 71 | return text; 72 | }); 73 | 74 | var label = svg.selectAll(".label") 75 | .data(graph.nodes) 76 | .enter().append("text") 77 | .attr("class", "label") 78 | .text(function (d){return '(' + d.index + ') ' + d.name; }) 79 | .call(d3cola.drag) 80 | 81 | d3cola.on("tick", function () { 82 | // draw directed edges with proper padding from node centers 83 | path.attr('d', function (d) { 84 | var deltaX = d.target.x - d.source.x, 85 | deltaY = d.target.y - d.source.y, 86 | dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), 87 | normX = deltaX / dist, 88 | normY = deltaY / dist; 89 | 90 | if(isNaN(normX)) normX = 0; 91 | if(isNaN(normY)) normY = 0; 92 | 93 | sourcePadding = d.source.width / 2, 94 | targetPadding = d.target.width / 2 + 2, 95 | sourceX = d.source.x + (sourcePadding * normX), 96 | sourceY = d.source.y + (sourcePadding * normY), 97 | targetX = d.target.x - (targetPadding * normX), 98 | targetY = d.target.y - (targetPadding * normY); 99 | 100 | // Defaults for normal edge. 101 | drx = 0, 102 | dry = 0, 103 | xRotation = 0, // degrees 104 | largeArc = 0, // 1 or 0 105 | sweep = 1; // 1 or 0 106 | 107 | // Self edge. 108 | if (d.source.x === d.target.x && d.source.y === d.target.y) { 109 | drx = dist; 110 | dry = dist; 111 | xRotation = -45; 112 | largeArc = 1; 113 | drx = 20; 114 | dry = 20; 115 | targetX = targetX + 1; 116 | targetY = targetY + 1; 117 | } 118 | return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY; 119 | }); 120 | 121 | node.attr("cx", function (d) { return d.x; }) 122 | .attr("cy", function (d) { return d.y; }) 123 | 124 | label 125 | .attr("x", function (d) { return d.x + 10; }) 126 | .attr("y", function (d) { return d.y - 10; }); 127 | }); 128 | }; 129 | -------------------------------------------------------------------------------- /docs/js/articles/playground/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.3.4/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"}, 4 | { type: 'script', url: "../../js/articles/neuroevolution/webcola.js"}, 5 | { type: 'script', url: "../../js/articles/playground/events.js"}, 6 | { type: 'script', url: "../../js/articles/playground/graph.js"}, 7 | { type: 'script', url: "../../js/articles/playground/neural.js"}, 8 | { type: 'css', url: "../../js/articles/playground/extra.css"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.addEventListener("load", fulfill); 23 | stylesheet.rel = 'stylesheet'; 24 | stylesheet.type = 'text/css'; 25 | stylesheet.href = link.url; 26 | stylesheet.media = "screen,print"; 27 | document.head.appendChild(stylesheet); 28 | } 29 | }); 30 | } 31 | loadScript(list.shift()).then(function() { 32 | if (list.length > 0) { 33 | require(list); 34 | } 35 | }) 36 | } 37 | 38 | require(scripts); 39 | -------------------------------------------------------------------------------- /docs/js/articles/playground/neural.js: -------------------------------------------------------------------------------- 1 | var { Network, methods, architect } = neataptic; 2 | 3 | var network = new Network(2, 1); 4 | $(document).ready(function () { 5 | refresh(); 6 | activate(); 7 | }); 8 | 9 | function mutate (method) { 10 | network.mutate(method); 11 | refresh(); 12 | activate(); 13 | } 14 | 15 | function activate () { 16 | var in1 = $('.input1').val(); 17 | var in2 = $('.input2').val(); 18 | 19 | if(in1 > 1 || in1 < 0 || in2 > 1 || in2 < 0){ 20 | alert('Inputs must be between 0 and 1!'); 21 | } 22 | 23 | var output = network.activate([in1, in2]); 24 | $('.output').text(output); 25 | } 26 | function refresh(){ 27 | drawGraph(network.graph($('.draw').width() / 1.4, $('.draw').height() / 1.4), '.draw'); 28 | } 29 | -------------------------------------------------------------------------------- /docs/js/articles/target-seekingai/field.js: -------------------------------------------------------------------------------- 1 | /* Global vars */ 2 | var players = []; 3 | var walker = new Walker(); 4 | var iteration = 0; 5 | var highestScore = 0; 6 | 7 | /** Setup the canvas */ 8 | function setup(){ 9 | var canvas = createCanvas(WIDTH, HEIGHT); 10 | canvas.parent('field'); 11 | initNeat(); 12 | 13 | // Do some initial mutation 14 | if(!USE_TRAINED_POP){ 15 | for(var i = 0; i < 1; i++) neat.mutate(); 16 | } 17 | 18 | startEvaluation(); 19 | } 20 | 21 | function draw(){ 22 | clear(); 23 | squareGrid(); 24 | 25 | // Check if evaluation is done 26 | if(iteration == ITERATIONS){ 27 | endEvaluation(); 28 | iteration = 0; 29 | } 30 | 31 | // Update and visualise players 32 | for(var i = players.length - 1; i >= 0; i--){ 33 | var player = players[i]; 34 | 35 | // Some players are eaten during the iteration 36 | player.update(); 37 | player.show(); 38 | } 39 | 40 | walker.update(); 41 | walker.show(); 42 | 43 | iteration++; 44 | } 45 | 46 | /** Draw a square grid with grey lines */ 47 | function squareGrid(){ 48 | stroke(204, 204, 204, 160); 49 | strokeWeight(1); 50 | fill(255); 51 | for(var x = 0; x < WIDTH/40; x++){ 52 | line(x * 40, 0, x * 40, HEIGHT); 53 | } 54 | for(var y = 0; y < HEIGHT/40; y++){ 55 | line(0, y * 40, WIDTH, y * 40); 56 | } 57 | noStroke(); 58 | } 59 | 60 | /** Calculate distance between two points */ 61 | function distance(x1, y1, x2, y2){ 62 | var dx = x1 - x2; 63 | var dy = y1 - y2; 64 | 65 | return Math.sqrt(dx * dx + dy * dy); 66 | } 67 | 68 | /** Get a relative color between red and green */ 69 | var activationColor = function(value, max){ 70 | var power = 1 - Math.min(value/max, 1); 71 | var color = [255, 255, 0] 72 | 73 | if(power < 0.5){ 74 | color[0] = 2 * power * 255; 75 | } else { 76 | color[1] = (1.0 - 2 * (power - 0.5)) * 255; 77 | } 78 | 79 | return color; 80 | } 81 | 82 | /** Get the angle from one point to another */ 83 | function angleToPoint(x1, y1, x2, y2){ 84 | d = distance(x1, y1, x2, y2); 85 | dx = (x2-x1) / d; 86 | dy = (y2-y1) / d; 87 | 88 | a = Math.acos(dx); 89 | a = dy < 0 ? 2 * Math.PI - a : a; 90 | return a; 91 | } 92 | 93 | /** Set the walker to a new location */ 94 | function mouseClicked(){ 95 | if(mouseX >= 0 && mouseX <= WIDTH && mouseY >= 0 && mouseY <= HEIGHT){ 96 | walker.x = mouseX; 97 | walker.y = mouseY; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /docs/js/articles/target-seekingai/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"}, 4 | { type: 'script', url: "../../js/articles/target-seekingai/main.js"}, 5 | { type: 'script', url: "../../js/articles/target-seekingai/population.js"}, 6 | { type: 'script', url: "../../js/articles/target-seekingai/player.js"}, 7 | { type: 'script', url: "../../js/articles/target-seekingai/walker.js"}, 8 | { type: 'script', url: "../../js/articles/target-seekingai/field.js"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.rel = 'stylesheet'; 23 | stylesheet.type = 'text/css'; 24 | stylesheet.href = link.url; 25 | stylesheet.media = "screen,print"; 26 | document.head.appendChild(stylesheet); 27 | } 28 | }); 29 | } 30 | loadScript(list.shift()).then(function() { 31 | if (list.length > 0) { 32 | require(list); 33 | } 34 | }) 35 | } 36 | 37 | require(scripts); 38 | -------------------------------------------------------------------------------- /docs/js/articles/target-seekingai/main.js: -------------------------------------------------------------------------------- 1 | /** Rename vars */ 2 | var Neat = neataptic.Neat; 3 | var Methods = neataptic.Methods; 4 | var Config = neataptic.Config; 5 | var Architect = neataptic.Architect; 6 | 7 | /** Turn off warnings */ 8 | Config.warnings = false; 9 | 10 | /** Settings */ 11 | var WIDTH = $('#field').width(); 12 | var HEIGHT = 500; 13 | var MAX_SPEED = 5; 14 | var START_X = WIDTH/2; 15 | var START_Y = HEIGHT/2; 16 | var SCORE_RADIUS = 100; 17 | 18 | // GA settings 19 | var PLAYER_AMOUNT = Math.round(2.3e-4 * WIDTH * HEIGHT); 20 | var ITERATIONS = 10e6; // should be ~250 for real use 21 | var MUTATION_RATE = 0.3; 22 | var ELITISM = Math.round(0.1 * PLAYER_AMOUNT); 23 | 24 | // Trained population 25 | var USE_TRAINED_POP = true; 26 | 27 | /** Global vars */ 28 | var neat; 29 | 30 | /** Construct the genetic algorithm */ 31 | function initNeat(){ 32 | neat = new Neat( 33 | 6, 1, 34 | null, 35 | { 36 | mutation: [ 37 | Methods.Mutation.ADD_NODE, 38 | Methods.Mutation.SUB_NODE, 39 | Methods.Mutation.ADD_CONN, 40 | Methods.Mutation.SUB_CONN, 41 | Methods.Mutation.MOD_WEIGHT, 42 | Methods.Mutation.MOD_BIAS, 43 | Methods.Mutation.MOD_ACTIVATION, 44 | Methods.Mutation.ADD_GATE, 45 | Methods.Mutation.SUB_GATE, 46 | Methods.Mutation.ADD_SELF_CONN, 47 | Methods.Mutation.SUB_SELF_CONN, 48 | Methods.Mutation.ADD_BACK_CONN, 49 | Methods.Mutation.SUB_BACK_CONN 50 | ], 51 | popsize: PLAYER_AMOUNT, 52 | mutationRate: MUTATION_RATE, 53 | elitism: ELITISM 54 | } 55 | ); 56 | 57 | if(USE_TRAINED_POP){ 58 | neat.population = population; 59 | } 60 | } 61 | 62 | /** Start the evaluation of the current generation */ 63 | function startEvaluation(){ 64 | players = []; 65 | highestScore = 0; 66 | 67 | for(var genome in neat.population){ 68 | genome = neat.population[genome]; 69 | new Player(genome); 70 | } 71 | 72 | walker.reset(); 73 | } 74 | 75 | /** End the evaluation of the current generation */ 76 | function endEvaluation(){ 77 | console.log('Generation:', neat.generation, '- average score:', Math.round(neat.getAverage())); 78 | console.log('Fittest score:', Math.round(neat.getFittest().score)); 79 | 80 | // Networks shouldn't get too big 81 | for(var genome in neat.population){ 82 | genome = neat.population[genome]; 83 | genome.score -= genome.nodes.length * SCORE_RADIUS / 10; 84 | } 85 | 86 | // Sort the population by score 87 | neat.sort(); 88 | 89 | // Init new pop 90 | var newPopulation = []; 91 | 92 | // Elitism 93 | for(var i = 0; i < neat.elitism; i++){ 94 | newPopulation.push(neat.population[i]); 95 | } 96 | 97 | // Breed the next individuals 98 | for(var i = 0; i < neat.popsize - neat.elitism; i++){ 99 | newPopulation.push(neat.getOffspring()); 100 | } 101 | 102 | // Replace the old population with the new population 103 | neat.population = newPopulation; 104 | neat.mutate(); 105 | 106 | neat.generation++; 107 | startEvaluation(); 108 | } 109 | -------------------------------------------------------------------------------- /docs/js/articles/target-seekingai/player.js: -------------------------------------------------------------------------------- 1 | function Player(genome){ 2 | this.x = START_X; 3 | this.y = START_Y; 4 | this.vx = 0; 5 | this.vy = 0; 6 | this.r = 6; 7 | 8 | this.brain = genome; 9 | this.brain.score = 0; 10 | 11 | players.push(this); 12 | } 13 | 14 | Player.prototype = { 15 | /** Update the stats */ 16 | update: function(){ 17 | var input = this.detect(); 18 | var output = this.brain.activate(input); 19 | 20 | var moveangle = output[0] * 2 * PI; 21 | 22 | // Calculate next position 23 | this.ax = Math.cos(moveangle); 24 | this.ay = Math.sin(moveangle); 25 | this.vx += this.ax; 26 | this.vy += this.ay; 27 | 28 | // Limit speeds to maximum speed 29 | this.vx = this.vx > MAX_SPEED ? MAX_SPEED : this.vx < -MAX_SPEED ? -MAX_SPEED : this.vx; 30 | this.vy = this.vy > MAX_SPEED ? MAX_SPEED : this.vy < -MAX_SPEED ? -MAX_SPEED : this.vy; 31 | 32 | this.x += this.vx; 33 | this.y += this.vy; 34 | 35 | // Limit position to width and height 36 | this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x; 37 | this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y; 38 | 39 | if(this.x == 0 || this.x == WIDTH) this.vx = -this.vx; 40 | if(this.y == 0 || this.y == HEIGHT) this.vy = -this.vy; 41 | 42 | this.score(); 43 | }, 44 | 45 | /** Calculate fitness of this players genome **/ 46 | score: function(){ 47 | var dist = distance(this.x, this.y, walker.x, walker.y); 48 | if(!isNaN(dist) && dist < SCORE_RADIUS){ 49 | this.brain.score += SCORE_RADIUS - dist; 50 | } 51 | 52 | // Replace highest score to visualise 53 | highestScore = this.brain.score > highestScore ? this.brain.score : highestScore; 54 | }, 55 | 56 | /** Display the player on the field, parts borrowed from the CodingTrain */ 57 | show: function(){ 58 | // Draw a triangle rotated in the direction of velocity 59 | var angle = angleToPoint(this.x, this.y, this.x + this.vx, this.y + this.vy) + HALF_PI; 60 | var color = activationColor(this.brain.score, highestScore); 61 | 62 | push(); 63 | translate(this.x, this.y); 64 | rotate(angle); 65 | 66 | fill(color); 67 | beginShape(); 68 | vertex(0, -this.r * 2); 69 | vertex(-this.r, this.r * 2); 70 | vertex(this.r, this.r * 2); 71 | endShape(CLOSE); 72 | 73 | pop(); 74 | }, 75 | 76 | /** Detect and normalize inputs */ 77 | detect: function(){ 78 | var dist = Math.sqrt(this.x, this.y, walker.x, walker.y) / Math.sqrt(WIDTH**2 + HEIGHT**2); 79 | var targetAngle = angleToPoint(this.x, this.y, walker.x, walker.y) / TWO_PI; 80 | var vx = (this.vx + MAX_SPEED) / MAX_SPEED; 81 | var vy = (this.vy + MAX_SPEED) / MAX_SPEED; 82 | var tvx = (walker.vx + MAX_SPEED) / MAX_SPEED; 83 | var tvy = (walker.vy + MAX_SPEED) / MAX_SPEED; 84 | 85 | // NaN checking 86 | targetAngle = isNaN(targetAngle) ? 0 : targetAngle; 87 | dist = isNaN(dist) ? 0 : dist; 88 | 89 | return [vx, vy, tvx, tvy, targetAngle, dist]; 90 | }, 91 | }; 92 | -------------------------------------------------------------------------------- /docs/js/articles/target-seekingai/walker.js: -------------------------------------------------------------------------------- 1 | function Walker(){ 2 | this.x = START_X; 3 | this.y = START_Y; 4 | this.vx = 0; 5 | this.vy = 0; 6 | 7 | this.r = 10; 8 | 9 | this.angle = Math.random() * Math.PI * 2; 10 | } 11 | 12 | Walker.prototype = { 13 | /** Update the stats */ 14 | update: function(){ 15 | if(Math.random() > 0.5){ 16 | this.angle += Math.random()* 2 -1; 17 | } 18 | 19 | // Calculate next position 20 | this.ax = Math.cos(this.angle); 21 | this.ay = Math.sin(this.angle); 22 | this.vx += this.ax; 23 | this.vy += this.ay; 24 | 25 | // Limit speeds to maximum speed 26 | this.vx = this.vx > MAX_SPEED/2 ? MAX_SPEED/2 : this.vx < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vx; 27 | this.vy = this.vy > MAX_SPEED/2 ? MAX_SPEED/2 : this.vy < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vy; 28 | 29 | this.x += this.vx; 30 | this.y += this.vy; 31 | 32 | // Limit position to width and height 33 | this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x; 34 | this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y; 35 | 36 | if(this.x == 0 || this.x == WIDTH){ 37 | this.vx = -this.vx; 38 | this.angle += PI; 39 | } 40 | if(this.y == 0 || this.y == HEIGHT){ 41 | this.vy = -this.vy; 42 | this.angle += PI; 43 | } 44 | }, 45 | 46 | reset: function(){ 47 | this.x = START_X; 48 | this.y = START_Y; 49 | this.vx = 0; 50 | this.vy = 0; 51 | 52 | this.angle = Math.random() * Math.PI * 2; 53 | }, 54 | 55 | 56 | /** Display the walker on the field */ 57 | show: function(){ 58 | fill(0); 59 | ellipse(this.x, this.y, this.r*2); 60 | 61 | // Score radius 62 | noFill(); 63 | stroke('lightgreen'); 64 | strokeWeight(2); 65 | ellipse(this.x, this.y, SCORE_RADIUS*2); 66 | noStroke(); 67 | }, 68 | }; 69 | -------------------------------------------------------------------------------- /docs/js/base.js: -------------------------------------------------------------------------------- 1 | function getSearchTerm() 2 | { 3 | var sPageURL = window.location.search.substring(1); 4 | var sURLVariables = sPageURL.split('&'); 5 | for (var i = 0; i < sURLVariables.length; i++) 6 | { 7 | var sParameterName = sURLVariables[i].split('='); 8 | if (sParameterName[0] == 'q') 9 | { 10 | return sParameterName[1]; 11 | } 12 | } 13 | } 14 | 15 | $(document).ready(function() { 16 | 17 | var search_term = getSearchTerm(), 18 | $search_modal = $('#mkdocs_search_modal'); 19 | 20 | if(search_term){ 21 | $search_modal.modal(); 22 | } 23 | 24 | // make sure search input gets autofocus everytime modal opens. 25 | $search_modal.on('shown.bs.modal', function () { 26 | $search_modal.find('#mkdocs-search-query').focus(); 27 | }); 28 | 29 | // Highlight.js 30 | hljs.initHighlightingOnLoad(); 31 | $('table').addClass('table table-striped table-hover'); 32 | 33 | // Improve the scrollspy behaviour when users click on a TOC item. 34 | $(".bs-sidenav a").on("click", function() { 35 | var clicked = this; 36 | setTimeout(function() { 37 | var active = $('.nav li.active a'); 38 | active = active[active.length - 1]; 39 | if (clicked !== active) { 40 | $(active).parent().removeClass("active"); 41 | $(clicked).parent().addClass("active"); 42 | } 43 | }, 50); 44 | }); 45 | 46 | }); 47 | 48 | 49 | $('body').scrollspy({ 50 | target: '.bs-sidebar', 51 | }); 52 | 53 | /* Toggle the `clicky` class on the body when clicking links to let us 54 | retrigger CSS animations. See ../css/base.css for more details. */ 55 | $('a').click(function(e) { 56 | $('body').toggleClass('clicky'); 57 | }); 58 | 59 | /* Prevent disabled links from causing a page reload */ 60 | $("li.disabled a").click(function() { 61 | event.preventDefault(); 62 | }); 63 | -------------------------------------------------------------------------------- /docs/mkdocs/js/search-results-template.mustache: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /docs/mkdocs/js/search.js: -------------------------------------------------------------------------------- 1 | require([ 2 | base_url + '/mkdocs/js/mustache.min.js', 3 | base_url + '/mkdocs/js/lunr.min.js', 4 | 'text!search-results-template.mustache', 5 | 'text!../search_index.json', 6 | ], function (Mustache, lunr, results_template, data) { 7 | "use strict"; 8 | 9 | function getSearchTerm() 10 | { 11 | var sPageURL = window.location.search.substring(1); 12 | var sURLVariables = sPageURL.split('&'); 13 | for (var i = 0; i < sURLVariables.length; i++) 14 | { 15 | var sParameterName = sURLVariables[i].split('='); 16 | if (sParameterName[0] == 'q') 17 | { 18 | return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20')); 19 | } 20 | } 21 | } 22 | 23 | var index = lunr(function () { 24 | this.field('title', {boost: 10}); 25 | this.field('text'); 26 | this.ref('location'); 27 | }); 28 | 29 | data = JSON.parse(data); 30 | var documents = {}; 31 | 32 | for (var i=0; i < data.docs.length; i++){ 33 | var doc = data.docs[i]; 34 | doc.location = base_url + doc.location; 35 | index.add(doc); 36 | documents[doc.location] = doc; 37 | } 38 | 39 | var search = function(){ 40 | 41 | var query = document.getElementById('mkdocs-search-query').value; 42 | var search_results = document.getElementById("mkdocs-search-results"); 43 | while (search_results.firstChild) { 44 | search_results.removeChild(search_results.firstChild); 45 | } 46 | 47 | if(query === ''){ 48 | return; 49 | } 50 | 51 | var results = index.search(query); 52 | 53 | if (results.length > 0){ 54 | for (var i=0; i < results.length; i++){ 55 | var result = results[i]; 56 | doc = documents[result.ref]; 57 | doc.base_url = base_url; 58 | doc.summary = doc.text.substring(0, 200); 59 | var html = Mustache.to_html(results_template, doc); 60 | search_results.insertAdjacentHTML('beforeend', html); 61 | } 62 | } else { 63 | search_results.insertAdjacentHTML('beforeend', "

No results found

"); 64 | } 65 | 66 | if(jQuery){ 67 | /* 68 | * We currently only automatically hide bootstrap models. This 69 | * requires jQuery to work. 70 | */ 71 | jQuery('#mkdocs_search_modal a').click(function(){ 72 | jQuery('#mkdocs_search_modal').modal('hide'); 73 | }); 74 | } 75 | 76 | }; 77 | 78 | var search_input = document.getElementById('mkdocs-search-query'); 79 | 80 | var term = getSearchTerm(); 81 | if (term){ 82 | search_input.value = term; 83 | search(); 84 | } 85 | 86 | search_input.addEventListener("keyup", search); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | https://wagenaartje.github.io/neataptic// 7 | 2017-10-21 8 | daily 9 | 10 | 11 | 12 | 13 | 14 | 15 | https://wagenaartje.github.io/neataptic//docs/ 16 | 2017-10-21 17 | daily 18 | 19 | 20 | 21 | https://wagenaartje.github.io/neataptic/ 22 | 23 | daily 24 | 25 | 26 | 27 | https://wagenaartje.github.io/neataptic/ 28 | 29 | daily 30 | 31 | 32 | 33 | https://wagenaartje.github.io/neataptic/ 34 | 35 | daily 36 | 37 | 38 | 39 | https://wagenaartje.github.io/neataptic/ 40 | 41 | daily 42 | 43 | 44 | 45 | https://wagenaartje.github.io/neataptic/ 46 | 47 | daily 48 | 49 | 50 | 51 | https://wagenaartje.github.io/neataptic//docs/neat/ 52 | 2017-10-21 53 | daily 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | https://wagenaartje.github.io/neataptic//articles/ 62 | 2017-10-21 63 | daily 64 | 65 | 66 | 67 | https://wagenaartje.github.io/neataptic//articles/neuroevolution/ 68 | 2017-10-21 69 | daily 70 | 71 | 72 | 73 | https://wagenaartje.github.io/neataptic//articles/targetseeking/ 74 | 2017-10-21 75 | daily 76 | 77 | 78 | 79 | https://wagenaartje.github.io/neataptic//articles/agario/ 80 | 2017-10-21 81 | daily 82 | 83 | 84 | 85 | https://wagenaartje.github.io/neataptic//articles/classifycolors/ 86 | 2017-10-21 87 | daily 88 | 89 | 90 | 91 | https://wagenaartje.github.io/neataptic//articles/playground/ 92 | 2017-10-21 93 | daily 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /graph/README.md: -------------------------------------------------------------------------------- 1 | ## Drawing a graph 2 | Visualising neural networks gives insight on which node have a larger effect on the output. And especially in evolving neural networks, it shows the characteristics of an ideal network. Setting up a graph is fairly easy: 3 | 4 | #### Index.html 5 | The html file should include [d3v3](http://d3js.org/d3.v3.min.js) and [webcola](http://marvl.infotech.monash.edu/webcola/cola.v3.min.js). Ofcourse you should also provide the neataptic.js file and the graph.js file from above. This is an example of the html file: 6 | ```html 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 | 27 | ``` 28 | 29 | #### Script.js 30 | If you want to work from a script, make sure to use the jquery `$( document ).ready()` function. Drawing the graph looks something like this then: 31 | 32 | ```javascript 33 | 34 | // Global var 35 | var network; 36 | 37 | $( document ).ready(function() { 38 | network = new neataptic.Architect.Perceptron(2, 10, 6, 5, 35, 1); 39 | drawGraph(network.graph(1000, 1000), '.draw'); 40 | }); 41 | ``` 42 | 43 | You can draw a graph using: 44 | ```javascript 45 | drawGraph(data, dom_element); 46 | ``` 47 | 48 | Retrieve your networks graph: 49 | ```javascript 50 | var data = myNetwork.graph(width, height); 51 | ``` 52 | 53 | #### Graph.js 54 | In the graph.js file, make sure to set the `WIDTH` and `HEIGHT` to the desired amount. 55 | 56 | ```javascript 57 | [...] 58 | var NODE_RADIUS = 7; // radius of circles on graph 59 | var REPEL_FORCE = 10; // force power between circles 60 | var LINK_DISTANCE = 100; // length of a connection 61 | 62 | var WIDTH = 1000; // width of your graph 63 | var HEIGHT = 500; // height of your graph 64 | [...] 65 | ``` 66 | 67 | #### Graph.css 68 | Make sure to include graph.css in your html file. This makes sure your connections are visible and makes the nodes more eye-appealing. 69 | 70 | ## Disable constraints 71 | Normally graphs look like the network on the left. If you want a more fluid design, disable constraints, and you'll get a graph like on the right: 72 | 73 | 74 | 75 | In `graph.js`, remove line 60: 76 | 77 | ```js 78 | .constraints(graph.constraints) // remove this line 79 | ``` 80 | 81 | This basically makes the input and output nodes less distinguishable. 82 | -------------------------------------------------------------------------------- /graph/graph.css: -------------------------------------------------------------------------------- 1 | .node { 2 | cursor: move; 3 | stroke-width: 1.5px; 4 | } 5 | .link { 6 | fill: none; 7 | stroke: #BDBDBD; 8 | stroke-width: 1.5px; 9 | opacity: 0.4; 10 | marker-end: url(#end-arrow); 11 | } 12 | .label { 13 | fill: #CCCCCC; 14 | font-size: 9px; 15 | text-anchor: middle; 16 | cursor: move; 17 | font-family: Arial; 18 | } 19 | #end-arrow{ 20 | opacity: 0.4; 21 | } 22 | .INPUT{ 23 | fill: #ff6666; 24 | stroke: #ff4d4d; 25 | } 26 | .OUTPUT{ 27 | fill : #ff8c66; 28 | stroke: #ff794d; 29 | } 30 | .LOGISTIC{ 31 | fill: #ffb366; 32 | stroke: #ffa64d; 33 | } 34 | .TANH{ 35 | fill: #ffd966; 36 | stroke: #ffd24d; 37 | } 38 | .IDENTITY{ 39 | fill: #ffff66; 40 | stroke: #ffff4d; 41 | } 42 | .STEP{ 43 | fill: #d9ff66; 44 | stroke: #d2ff4d; 45 | } 46 | .RELU{ 47 | fill: #b3ff66; 48 | stroke: #a6ff4d; 49 | } 50 | .SOFTSIGN{ 51 | fill: #8cff66; 52 | stroke: #79ff4d; 53 | } 54 | .SINUSOID{ 55 | fill: #66ff66; 56 | stroke: #4dff4d; 57 | } 58 | .GAUSSIAN{ 59 | fill: #66ff8c; 60 | stroke: #4dff79; 61 | } 62 | .BENT_IDENTITY{ 63 | fill: #66ffd9; 64 | stroke: #4dffd2; 65 | } 66 | .BIPOLAR{ 67 | fill: #66d9ff; 68 | stroke: #4dd2ff; 69 | } 70 | .BIPOLAR_SIGMOID{ 71 | fill: #66b3ff; 72 | stroke: #4da6ff; 73 | } 74 | .HARD_TANH{ 75 | fill: #668cff; 76 | stroke: #4d79ff; 77 | } 78 | .ABSOLUTE{ 79 | fill: #6666ff; 80 | stroke: #4d4dff; 81 | } 82 | .GATE{ 83 | fill: #003300; 84 | stroke: #001a00; 85 | } 86 | .CONSTANT{ 87 | fill: #ff00ff; 88 | stroke: #e600e6; 89 | } 90 | .INVERSE{ 91 | fill: #ff0080; 92 | stroke: #e60073; 93 | } 94 | .SELU{ 95 | fill: #ff0040; 96 | stroke: #e60039; 97 | } 98 | -------------------------------------------------------------------------------- /graph/graph.js: -------------------------------------------------------------------------------- 1 | var NODE_RADIUS = 7; 2 | var GATE_RADIUS = 2; 3 | var REPEL_FORCE = 0; 4 | var LINK_DISTANCE = 100; 5 | 6 | var WIDTH = 1000; 7 | var HEIGHT = 500; 8 | 9 | function drawGraph (graph, panel) { 10 | var d3cola = cola.d3adaptor() 11 | .avoidOverlaps(true) 12 | .size([WIDTH, HEIGHT]); 13 | 14 | var svg = d3.select(panel); 15 | 16 | d3.selectAll(panel + '> *').remove(); 17 | 18 | // define arrow markers for graph links 19 | svg.append('svg:defs').append('svg:marker') 20 | .attr('id', 'end-arrow') 21 | .attr('viewBox', '0 -5 10 10') 22 | .attr('refX', 6) 23 | .attr('markerWidth', 4) 24 | .attr('markerHeight', 4) 25 | .attr('orient', 'auto') 26 | .append('svg:path') 27 | .attr('d', 'M0,-5L10,0L0,5'); 28 | 29 | graph.nodes.forEach(function (v) { 30 | v.height = v.width = 2 * (v.name === 'GATE' ? GATE_RADIUS : NODE_RADIUS); 31 | }); 32 | 33 | d3cola 34 | .nodes(graph.nodes) 35 | .links(graph.links) 36 | .constraints(graph.constraints) 37 | .symmetricDiffLinkLengths(REPEL_FORCE) 38 | .linkDistance(LINK_DISTANCE) 39 | .start(10, 15, 20); 40 | 41 | var path = svg.selectAll('.link') 42 | .data(graph.links) 43 | .enter().append('svg:path') 44 | .attr('class', 'link'); 45 | 46 | path.append('title') 47 | .text(function (d) { 48 | var text = ''; 49 | text += 'Weight: ' + Math.round(d.weight * 1000) / 1000 + '\n'; 50 | text += 'Source: ' + d.source.id + '\n'; 51 | text += 'Target: ' + d.target.id; 52 | return text; 53 | }); 54 | 55 | var node = svg.selectAll('.node') 56 | .data(graph.nodes) 57 | .enter().append('circle') 58 | .attr('class', function (d) { 59 | return 'node ' + d.name; 60 | }) 61 | .attr('r', function (d) { 62 | return d.name === 'GATE' ? GATE_RADIUS : NODE_RADIUS; 63 | }) 64 | 65 | .call(d3cola.drag); 66 | 67 | node.append('title') 68 | .text(function (d) { 69 | var text = ''; 70 | text += 'Activation: ' + Math.round(d.activation * 1000) / 1000 + '\n'; 71 | text += 'Bias: ' + Math.round(d.bias * 1000) / 1000 + '\n'; 72 | text += 'Position: ' + d.id; 73 | return text; 74 | }); 75 | 76 | var label = svg.selectAll('.label') 77 | .data(graph.nodes) 78 | .enter().append('text') 79 | .attr('class', 'label') 80 | .text(function (d) { 81 | return '(' + d.index + ') ' + d.name; 82 | }) 83 | .call(d3cola.drag); 84 | 85 | d3cola.on('tick', function () { 86 | // draw directed edges with proper padding from node centers 87 | path.attr('d', function (d) { 88 | var deltaX = d.target.x - d.source.x; 89 | var deltaY = d.target.y - d.source.y; 90 | var dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY); 91 | var normX = deltaX / dist; 92 | var normY = deltaY / dist; 93 | 94 | if (isNaN(normX)) normX = 0; 95 | if (isNaN(normY)) normY = 0; 96 | 97 | var sourcePadding = d.source.width / 2; 98 | var targetPadding = d.target.width / 2 + 2; 99 | var sourceX = d.source.x + (sourcePadding * normX); 100 | var sourceY = d.source.y + (sourcePadding * normY); 101 | var targetX = d.target.x - (targetPadding * normX); 102 | var targetY = d.target.y - (targetPadding * normY); 103 | 104 | // Defaults for normal edge. 105 | var drx = 0; 106 | var dry = 0; 107 | var xRotation = 0; // degrees 108 | var largeArc = 0; // 1 or 0 109 | var sweep = 1; // 1 or 0 110 | 111 | // Self edge. 112 | if (d.source.x === d.target.x && d.source.y === d.target.y) { 113 | xRotation = -45; 114 | largeArc = 1; 115 | drx = 20; 116 | dry = 20; 117 | targetX = targetX + 1; 118 | targetY = targetY + 1; 119 | } 120 | return 'M' + sourceX + ',' + sourceY + 'A' + drx + ',' + dry + ' ' + xRotation + ',' + largeArc + ',' + sweep + ' ' + targetX + ',' + targetY; 121 | }); 122 | 123 | node 124 | .attr('cx', function (d) { 125 | return d.x; 126 | }) 127 | .attr('cy', function (d) { 128 | return d.y; 129 | }); 130 | 131 | label 132 | .attr('x', function (d) { 133 | return d.x + 10; 134 | }) 135 | .attr('y', function (d) { 136 | return d.y - 10; 137 | }); 138 | }); 139 | } 140 | -------------------------------------------------------------------------------- /mkdocs/mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Neataptic.js 2 | theme: null 3 | theme_dir: theme 4 | repo_url: https://github.com/wagenaartje/neataptic 5 | site_url: https://wagenaartje.github.io/neataptic/ 6 | site_author: 'Thomas Wagenaar' 7 | site_description: 'Documentation for Neataptic, the Javascript neural network library' 8 | docs_dir: templates 9 | edit_uri: edit/master/mkdocs/templates/ 10 | 11 | google_analytics: ['UA-51480408-2', 'wagenaartje.github.io'] 12 | 13 | extra_css: 14 | - css/extra.css 15 | 16 | markdown_extensions: 17 | - meta 18 | 19 | pages: 20 | - Home: index.md 21 | - Docs: 22 | - Docs: docs/index.md 23 | - Tutorials: 24 | - Tutorials: docs/tutorials/tutorials.md 25 | - Training: docs/tutorials/training.md 26 | - Evolution: docs/tutorials/evolution.md 27 | - Normalization: docs/tutorials/normalization.md 28 | - Visualization: docs/tutorials/visualization.md 29 | - Important functions: 30 | - Important functions: docs/important/important.md 31 | - Train: docs/important/train.md 32 | - Evolve: docs/important/evolve.md 33 | - Built-in networks: 34 | - Built-in networks: docs/builtins/builtins.md 35 | - Perceptron: docs/builtins/perceptron.md 36 | - LSTM: docs/builtins/lstm.md 37 | - GRU: docs/builtins/gru.md 38 | - NARX: docs/builtins/narx.md 39 | - Random: docs/builtins/random.md 40 | - Hopfield: docs/builtins/hopfield.md 41 | - Architecture: 42 | - Architecture: docs/architecture/architecture.md 43 | - Construct: docs/architecture/construct.md 44 | - Network: docs/architecture/network.md 45 | - Layer: docs/architecture/layer.md 46 | - Group: docs/architecture/group.md 47 | - Node: docs/architecture/node.md 48 | - Connection: docs/architecture/connection.md 49 | - Methods: 50 | - Methods: docs/methods/methods.md 51 | - Regularization: docs/methods/regularization.md 52 | - Mutation: docs/methods/mutation.md 53 | - Selection: docs/methods/selection.md 54 | - Activation: docs/methods/activation.md 55 | - Cost: docs/methods/cost.md 56 | - Connection: docs/architecture/connection.md 57 | - Gating: docs/methods/gating.md 58 | - Rate: docs/methods/rate.md 59 | - NEAT: docs/neat.md 60 | - Articles: 61 | - Articles: articles/index.md 62 | - Neuroevolution : articles/neuroevolution.md 63 | - 'Target-seeking AI': articles/targetseeking.md 64 | - 'Agar.io AI': articles/agario.md 65 | - 'Classify colors': articles/classifycolors.md 66 | - Playground: articles/playground.md 67 | -------------------------------------------------------------------------------- /mkdocs/templates/articles/classifycolors.md: -------------------------------------------------------------------------------- 1 | description: Classify different colors through genetic algorithms 2 | authors: Thomas Wagenaar 3 | keywords: color classification, genetic-algorithm, NEAT, Neataptic 4 | 5 | Classifying is something a neural network can do quite well. In this article 6 | I will demonstrate how you can set up the evolution process of a neural network 7 | that learns to classify colors with Neataptic. 8 | 9 | Colors: 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Start evolution 20 | 21 |
Iteration: 0                                                        Best-fitness: 0
22 |
23 |
24 |

Set sorted by color

25 |
26 |
27 |
28 |
29 |

Set sorted by NN

30 |
31 |
32 |
33 |
34 | 35 |
36 | 37 | ### How it works 38 | The algorithm to this classification is actually _pretty_ easy. One of my biggest 39 | problem was generating the colors, however I stumbled upon [this](https://github.com/davidmerfield/randomColor) 40 | Javascript library that allows you to generate colors randomly by name - exactly 41 | what I needed (but it also created a problem, read below). So I used it to create 42 | a training set: 43 | 44 | ```javascript 45 | function createSet(){ 46 | var set = []; 47 | 48 | for(index in COLORS){ 49 | var color = COLORS[index]; 50 | 51 | var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'}); 52 | 53 | for(var random in randomColors){ 54 | var rgb = randomColors[random]; 55 | random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(','); 56 | for(var y in random) random[y] = random[y]/255; 57 | 58 | var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0); 59 | output[index] = 1; 60 | 61 | set.push({ input: random, output: output, color: color, rgb: rgb}); 62 | } 63 | } 64 | 65 | return set; 66 | } 67 | ``` 68 | 69 | _COLORS_ is an array storing all color names in strings. The possible colors are 70 | listed above. Next, we convert this rgb string to an array and normalize the 71 | values between 0 and 1. Last of all, we normalize the colors using 72 | [one-hot encoding](https://www.quora.com/What-is-one-hot-encoding-and-when-is-it-used-in-data-science). 73 | Please note that the `color`and `rgb` object attributes are irrelevant for the algorithm. 74 | 75 | ```javascript 76 | network.evolve(set, { 77 | iterations: 1, 78 | mutationRate: 0.6, 79 | elisitm: 5, 80 | popSize: 100, 81 | mutation: methods.mutation.FFW, 82 | cost: methods.cost.MSE 83 | }); 84 | ``` 85 | 86 | Now we create the built-in genetic algorithm in neataptic.js. We define 87 | that we want to use all possible mutation methods and set the mutation rate 88 | higher than normal. Sprinkle in some elitism and double the default population 89 | size. Experiment with the parameters yourself, maybe you'll find even better parameters! 90 | 91 | The fitness function is the most vital part of the algorithm. It basically 92 | calculates the [Mean Squared Error](https://en.wikipedia.org/wiki/Mean_squared_error) 93 | of the entire set. Neataptic saves the programming of this fitness calculation. 94 | At the same time the default `growth` parameter is used, so the networks will 95 | get penalized for being too large. 96 | 97 | And putting together all this code will create a color classifier. 98 | -------------------------------------------------------------------------------- /mkdocs/templates/articles/index.md: -------------------------------------------------------------------------------- 1 | description: Articles featuring projects that were created with Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: Neataptic, JavaScript, library 4 | 5 | Welcome to the articles page! Every now and then, articles will be posted here 6 | showing for what kind of projects Neataptic _could_ be used. Neataptic is 7 | excellent for the development of AI for browser games for example. 8 | 9 | If you want to post your own article here, feel free to create a pull request 10 | or an isse on the [repo page](https://github.com/wagenaartje/neataptic)! 11 | -------------------------------------------------------------------------------- /mkdocs/templates/articles/neuroevolution.md: -------------------------------------------------------------------------------- 1 | description: A list of neuro-evolution algorithms set up with Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: genetic-algorithm, Neat, JavaScript, Neataptic, neuro-evolution 4 | 5 | This page shows some neuro-evolution examples. Please note that not every example 6 | may always be successful. More may be added in the future! 7 | 8 |
9 |
10 | 1: Uphill and downhill 11 |
12 |
13 |

This neural network gets taught to increase the input by 0.2 until 1.0 is reached, then it must decrease the input by 2.0.

14 | 15 | 16 |
17 | 18 | 19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 | 2: Count to ten 27 |
28 |
29 |

This neural network gets taught to wait 9 inputs of 0, to output 1 at input number 10.

30 | 31 | 32 |
33 | 34 | 35 | 36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 | 3: Vowel vs. consonants classification 44 |
45 |
46 |

This neural network gets taught to classify if a letter of the alphabet is a vowel or not. The data is one-hot-encoded.

47 | 48 | 49 |
50 | 51 | 52 | 53 |
54 | 55 |
56 |
57 | 58 | 71 | -------------------------------------------------------------------------------- /mkdocs/templates/articles/playground.md: -------------------------------------------------------------------------------- 1 | description: Play around with neural-networks built with Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: mutate, neural-network, machine-learning, playground, Neataptic 4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 |
40 |
41 | 42 |
43 |
44 | 45 |
46 |
47 | 48 |
49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 |
62 | input1 63 | 64 |
65 |
66 | input2 67 | 68 |
69 |
70 |
71 | 72 |
73 |
74 |
Output: 
75 | 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/architecture/architecture.md: -------------------------------------------------------------------------------- 1 | If you want to built your completely custom neural network; this is the place to be. 2 | You can build your network from the bottom, using nodes and connections, or you can 3 | ease up the process by using groups and layers. 4 | 5 | * [Connection](connection.md) 6 | * [Node](node.md) 7 | * [Group](group.md) 8 | * [Layer](layer.md) 9 | * [Network](network.md) 10 | * [Construct](construct.md) 11 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/architecture/connection.md: -------------------------------------------------------------------------------- 1 | description: Documentation of the Connection instance in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: connection, neural-network, architecture, synapse, weight 4 | 5 | A connection instance defines the connection between two nodes. All you have to do is pass on a from and to node, and optionally a weight. 6 | 7 | ```javascript 8 | var B = new Node(); 9 | var C = new Node(); 10 | var connection = new Connection(A, B, 0.5); 11 | ``` 12 | 13 | Connection properties: 14 | 15 | Property | contains 16 | -------- | -------- 17 | from | connection origin node 18 | to | connection destination node 19 | weight | the weight of the connection 20 | gater | the node gating this connection 21 | gain | for gating, gets multiplied with weight 22 | 23 | ### Connection methods 24 | There are three connection methods: 25 | 26 | * **methods.connection.ALL_TO_ALL** connects all nodes from group `x` to all nodes from group `y` 27 | * **methods.connection.ALL_TO_ELSE** connects every node from group `x` to all nodes in the same group except itself 28 | * **methods.connection.ONE_TO_ONE** connects every node in group `x` to one node in group `y` 29 | 30 | Every one of these connection methods can also be used on the group itself! (`x.connect(x, METHOD)`) 31 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/architecture/construct.md: -------------------------------------------------------------------------------- 1 | description: Documentation on how to construct your own network with Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: neural-network, architecture, node, build, connection 4 | 5 | 6 | For example, I want to have a network that looks like a square: 7 | 8 | ```javascript 9 | var A = new Node(); 10 | var B = new Node(); 11 | var C = new Node(); 12 | var D = new Node(); 13 | 14 | // Create connections 15 | A.connect(B); 16 | A.connect(C); 17 | B.connect(D); 18 | C.connect(D); 19 | 20 | // Construct a network 21 | var network = architect.Construct([A, B, C, D]); 22 | ``` 23 | 24 | And voila, basically a square, but stretched out, right? 25 | 26 | ![Square](https://i.gyazo.com/c91f9ce9df69f6e085535a642355b88a.png) 27 | 28 | The `construct()` function looks for nodes that have no input connections, and labels them as an input node. The same for output nodes: it looks for nodes without an output connection (and gating connection), and labels them as an output node! 29 | 30 | **You can also create networks with groups!** This speeds up the creation process and saves lines of code. 31 | 32 | ```javascript 33 | // Initialise groups of nodes 34 | var A = new Group(4); 35 | var B = new Group(2); 36 | var C = new Group(6); 37 | 38 | // Create connections between the groups 39 | A.connect(B); 40 | A.connect(C); 41 | B.connect(C); 42 | 43 | // Construct a network 44 | var network = architect.Construct([A, B, C, D]); 45 | ``` 46 | 47 | Keep in mind that you must always specify your input groups/nodes in **activation order**. Input and output nodes will automatically get sorted out, but all hidden nodes will be activated in the order that they were given. 48 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/architecture/group.md: -------------------------------------------------------------------------------- 1 | description: Documentation of the Group instance in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: group, neurons, nodes, neural-network, activation 4 | 5 | 6 | A group instance denotes a group of nodes. Beware: once a group has been used to construct a network, the groups will fall apart into individual nodes. They are purely for the creation and development of networks. A group can be created like this: 7 | 8 | ```javascript 9 | // A group with 5 nodes 10 | var A = new Group(5); 11 | ``` 12 | 13 | Group properties: 14 | 15 | Property | contains 16 | -------- | -------- 17 | nodes | an array of all nodes in the group 18 | connections | dictionary with connections 19 | 20 | ### activate 21 | Will activate all the nodes in the network. 22 | 23 | ```javascript 24 | myGroup.activate(); 25 | 26 | // or (array length must be same length as nodes in group) 27 | myGroup.activate([1, 0, 1]); 28 | ``` 29 | 30 | ### propagate 31 | Will backpropagate all nodes in the group, make sure the group receives input from another group or node! 32 | 33 | ```javascript 34 | myGroup.propagate(rate, momentum, target); 35 | ``` 36 | 37 | The target argument is optional. An example would be: 38 | 39 | ```javascript 40 | var A = new Group(2); 41 | var B = new Group(3); 42 | 43 | A.connect(B); 44 | 45 | A.activate([1,0]); // set the input 46 | B.activate(); // get the output 47 | 48 | // Then teach the network with learning rate and wanted output 49 | B.propagate(0.3, 0.9, [0,1]); 50 | ``` 51 | 52 | The default value for momentum is `0`. Read more about momentum on the 53 | [regularization page](../methods/regularization.md). 54 | 55 | ### connect 56 | Creates connections between this group and another group or node. There are different connection methods for groups, check them out [here](connection.md). 57 | 58 | ```javascript 59 | var A = new Group(4); 60 | var B = new Group(5); 61 | 62 | A.connect(B, methods.connection.ALL_TO_ALL); // specifying a method is optional 63 | ``` 64 | 65 | ### disconnect 66 | (not yet implemented) 67 | 68 | ### gate 69 | Makes the nodes in a group gate an array of connections between two other groups. You have to specify a gating method, which can be found [here](../methods/gating.md). 70 | 71 | ```javascript 72 | var A = new Group(2); 73 | var B = new Group(6); 74 | 75 | var connections = A.connect(B); 76 | 77 | var C = new Group(2); 78 | 79 | // Gate the connections between groups A and B 80 | C.gate(connections, methods.gating.INPUT); 81 | ``` 82 | 83 | ### set 84 | Sets the properties of all nodes in the group to the given values, e.g.: 85 | 86 | ```javascript 87 | var group = new Group(4); 88 | 89 | // All nodes in 'group' now have a bias of 1 90 | group.set({bias: 1}); 91 | ``` 92 | 93 | ### disconnect 94 | Disconnects the group from another group or node. Can be twosided. 95 | 96 | ```javascript 97 | var A = new Group(4); 98 | var B = new Node(); 99 | 100 | // Connect them 101 | A.connect(B); 102 | 103 | // Disconnect them 104 | A.disconnect(B); 105 | 106 | // Twosided connection 107 | A.connect(B); 108 | B.connect(A); 109 | 110 | // Disconnect from both sides 111 | A.disconnect(B, true); 112 | ``` 113 | 114 | ### clear 115 | Clears the context of the group. Useful for predicting timeseries with LSTM's. 116 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/architecture/layer.md: -------------------------------------------------------------------------------- 1 | description: Documentation of the Layer instance in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: LSTM, GRU, architecture, neural-network, recurrent 4 | 5 | 6 | Layers are pre-built architectures that allow you to combine different network 7 | architectures into óne network. At this moment, there are 3 layers (more to come soon!): 8 | 9 | ```javascript 10 | Layer.Dense 11 | Layer.LSTM 12 | Layer.GRU 13 | Layer.Memory 14 | ``` 15 | 16 | Check out the options and details for each layer below. 17 | 18 | ### Constructing your own network with layers 19 | You should always start your network with a `Dense` layer and always end it with 20 | a `Dense` layer. You can connect layers with each other just like you can connect 21 | nodes and groups with each other. This is an example of a custom architecture 22 | built with layers: 23 | 24 | ```javascript 25 | var input = new Layer.Dense(1); 26 | var hidden1 = new Layer.LSTM(5); 27 | var hidden2 = new Layer.GRU(1); 28 | var output = new Layer.Dense(1); 29 | 30 | // connect however you want 31 | input.connect(hidden1); 32 | hidden1.connect(hidden2); 33 | hidden2.connect(output); 34 | 35 | var network = architect.Construct([input, hidden1, hidden2, output]); 36 | ``` 37 | 38 | ### Layer.Dense 39 | The dense layer is a regular layer. 40 | 41 | ```javascript 42 | var layer = new Layer.Dense(size); 43 | ``` 44 | 45 | ### Layer.LSTM 46 | The LSTM layer is very useful for detecting and predicting patterns over long 47 | time lags. This is a recurrent layer. More info? Check out the [LSTM](../builtins/lstm.md) page. 48 | 49 | ```javascript 50 | var layer = new Layer.LSTM(size); 51 | ``` 52 | 53 | Be aware that using `Layer.LSTM` is worse than using `architect.LSTM`. See issue [#25](https://github.com/wagenaartje/neataptic/issues/25). 54 | 55 | ### Layer.GRU 56 | The GRU layer is similar to the LSTM layer, however it has no memory cell and only 57 | two gates. It is also a recurrent layer that is excellent for timeseries prediction. 58 | More info? Check out the [GRU](../builtins/gru.md) page. 59 | 60 | ```javascript 61 | var layer = new Layer.GRU(size); 62 | ``` 63 | 64 | ### Layer.Memory 65 | The Memory layer is very useful if you want your network to remember a number of 66 | previous inputs in an absolute way. For example, if you set the `memory` option to 67 | 3, it will remember the last 3 inputs in the same state as they were inputted. 68 | 69 | ```javascript 70 | var layer = new Layer.Memory(size, memory); 71 | ``` 72 | 73 | The input layer to the memory layer should always have the same size as the memory size. 74 | The memory layer will output a total of `size * memory` values. 75 | 76 | > This page is incomplete. There is no description on the functions you can use 77 | on this instance yet. Feel free to add the info (check out src/layer.js) 78 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/builtins.md: -------------------------------------------------------------------------------- 1 | If you are unfamiliar with building networks layer by layer, you can use the 2 | preconfigured networks. These networks will also be built layer by layer behind 3 | the screens, but for the user they are all a simple one line function. At this 4 | moment, Neataptic offers 6 preconfigured networks. 5 | 6 | * [GRU](gru.md) 7 | * [Hopfield](hopfield.md) 8 | * [LSTM](lstm.md) 9 | * [NARX](narx.md) 10 | * [Perceptron](perceptron.md) 11 | * [Random](random.md) 12 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/gru.md: -------------------------------------------------------------------------------- 1 | description: How to use the Gated Recurrent Unit network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: recurrent, neural-network, GRU, architecture 4 | 5 | > Please be warned: GRU is still being tested, it might not always work for your dataset. 6 | 7 | The Gated Recurrent Unit network is very similar to the LSTM network. GRU networks have óne gate less and no selfconnections. Similarly to LSTM's, GRU's are well-suited to classify, process and predict time series when there are very long time lags of unknown size between important events. 8 | 9 | 10 | 11 | To use this architecture you have to set at least one input node, one gated recurrent unit assembly, and an output node. The gated recurrent unit assembly consists of seven nodes: input, update gate, inverse update gate, reset gate, memorycell, output and previous output memory. 12 | 13 | ```javascript 14 | var myLSTM = new architect.GRU(2,6,1); 15 | ``` 16 | 17 | Also you can set many layers of gated recurrent units: 18 | 19 | ```javascript 20 | var myLSTM = new architect.GRU(2, 4, 4, 4, 1); 21 | ``` 22 | 23 | The above network has 3 hidden layers, with 4 GRU assemblies each. It has two inputs and óne output. 24 | 25 | While training sequences or timeseries prediction to a GRU, make sure you set the `clear` option to true while training. Additionally, through trial and error, I have discovered that using a lower rate than normal works best for GRU networks (e.g. `0.1` instead of `0.3`). 26 | 27 | This is an example of training the sequence XOR gate to a a GRU network: 28 | 29 | ```js 30 | var trainingSet = [ 31 | { input: [0], output: [0]}, 32 | { input: [1], output: [1]}, 33 | { input: [1], output: [0]}, 34 | { input: [0], output: [1]}, 35 | { input: [0], output: [0]} 36 | ]; 37 | 38 | var network = new architect.GRU(1,1,1); 39 | 40 | // Train a sequence: 00100100.. 41 | network.train(trainingSet, { 42 | log: 1, 43 | rate: 0.1, 44 | error: 0.005, 45 | iterations: 3000, 46 | clear: true 47 | }); 48 | ``` 49 | [Run it here yourself!](https://jsfiddle.net/dzywa15x/) 50 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/hopfield.md: -------------------------------------------------------------------------------- 1 | description: How to use the Hopfield network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: feed-forward, neural-network, hopfield, architecture 4 | 5 | > This network might be removed soon 6 | 7 | The hopfield architecture is excellent for remembering patterns. Given an input, it will output the most similar pattern it was trained. The output will always be binary, due to the usage of the `Activation.STEP` function. 8 | 9 | ```javascript 10 | var network = architect.Hopfield(10); 11 | var trainingSet = [ 12 | { input: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], output: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] }, 13 | { input: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], output: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0] } 14 | ]; 15 | 16 | network.train(trainingSet); 17 | 18 | network.activate([0,1,0,1,0,1,0,1,1,1]); // [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] 19 | network.activate([1,1,1,1,1,0,0,1,0,0]); // [1, 1, 1, 1, 1, 0, 0, 0, 0, 0] 20 | ``` 21 | 22 | The input for the training set must always be the same as the output. 23 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/lstm.md: -------------------------------------------------------------------------------- 1 | description: How to use the Long Short-Term Memory network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: recurrent, neural-network, LSTM, architecture 4 | 5 | The [long short-term memory](http://en.wikipedia.org/wiki/Long_short_term_memory) is an architecture well-suited to learn from experience to classify, process and predict time series when there are very long time lags of unknown size between important events. 6 | 7 | ![Long short-term memory cell](https://i.gyazo.com/9d4310c6175006d1bad5669d0249061c.png) 8 | 9 | To use this architecture you have to set at least one input node, one memory block assembly (consisting of four nodes: input gate, memory cell, forget gate and output gate), and an output node. 10 | 11 | ```javascript 12 | var myLSTM = new architect.LSTM(2,6,1); 13 | ``` 14 | 15 | Also you can set many layers of memory blocks: 16 | 17 | ```javascript 18 | var myLSTM = new architect.LSTM(2, 4, 4, 4, 1); 19 | ``` 20 | 21 | That LSTM network has 3 memory block assemblies, with 4 memory cells each, and their own input gates, memory cells, forget gates and output gates. 22 | 23 | You can pass options if desired like so: 24 | 25 | ```javascript 26 | var options = { 27 | memoryToMemory: false, // default is false 28 | outputToMemory: false, // default is false 29 | outputToGates: false, // default is false 30 | inputToOutput: true, // default is true 31 | inputToDeep: true // default is true 32 | }; 33 | 34 | var myLSTM = new architect.LSTM(2, 4, 4, 4, 1, options); 35 | ``` 36 | 37 | While training sequences or timeseries prediction to a LSTM, make sure you set the `clear` option to true while training. [See an example of sequence prediction here.](https://jsfiddle.net/9t2787k5/4/) 38 | 39 | This is an example of character-by-character typing by an LSTM: [JSFiddle](https://jsfiddle.net/k23zbf0f/8/) 40 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/narx.md: -------------------------------------------------------------------------------- 1 | description: How to use the Nonlinear Autoregressive Exogenous model network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: recurrent, neural-network, NARX, architecture 4 | 5 | Just like LSTM's, [NARX networks](https://en.wikipedia.org/wiki/Nonlinear_autoregressive_exogenous_model) are very good at timeseries prediction. That is because they use previous inputs and their corresponding output values as the next input to the hidden layer. 6 | 7 | ![](http://i.imgur.com/qcLyVcw.png) 8 | 9 | The constructor looks like this: 10 | 11 | ```js 12 | var network = new architect.NARX(inputSize, hiddenLayers, outputSize, previousInput, previousOutput); 13 | ``` 14 | 15 | A quick explanation of each argument: 16 | 17 | * `inputSize`: the amount of input nodes 18 | * `hiddenLayers`: an array containing hidden layer sizes, e.g. `[10,20,10]`. If only one hidden layer, can be a number (of nodes) 19 | * `outputSize`: the amount of output nodes 20 | * `previousInput`: the amount of previous inputs you want it to remember 21 | * `previousOutput`: the amount of previous outputs you want it to remember 22 | 23 | Example: 24 | 25 | ```javascript 26 | var narx = new architect.NARX(1, 5, 1, 3, 3); 27 | 28 | // Train the XOR gate (in sequence!) 29 | var trainingData = [ 30 | { input: [0], output: [0] }, 31 | { input: [0], output: [0] }, 32 | { input: [0], output: [1] }, 33 | { input: [1], output: [0] }, 34 | { input: [0], output: [0] }, 35 | { input: [0], output: [0] }, 36 | { input: [0], output: [1] }, 37 | ]; 38 | 39 | narx.train(trainingData, { 40 | log: 1, 41 | iterations: 3000, 42 | error: 0.03, 43 | rate: 0.05 44 | }); 45 | ``` 46 | [Run it here](https://jsfiddle.net/wagenaartje/1o7t91yk/2/) 47 | 48 | The NARX network type has 'constant' nodes. These nodes won't affect the weight of their incoming connections and their bias will never change. Please do note that mutation CAN change all of these. 49 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/perceptron.md: -------------------------------------------------------------------------------- 1 | description: How to use the Perceptron network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: feed-forward, neural-network, perceptron, MLP, architecture 4 | 5 | This architecture allows you to create multilayer perceptrons, also known as feed-forward neural networks. They consist of a sequence of layers, each fully connected to the next one. 6 | 7 | ![multilayer perceptron](http://www.codeproject.com/KB/dotnet/predictor/network.jpg "Multilayer Perceptron Architecture") 8 | 9 | You have to provide a minimum of 3 layers (input, hidden and output), but you can use as many hidden layers as you wish. This is a `Perceptron` with 2 neurons in the input layer, 3 neurons in the hidden layer, and 1 neuron in the output layer: 10 | 11 | ```javascript 12 | var myPerceptron = new architect.Perceptron(2,3,1); 13 | ``` 14 | 15 | And this is a deep multilayer perceptron with 2 neurons in the input layer, 4 hidden layers with 10 neurons each, and 1 neuron in the output layer 16 | 17 | ```javascript 18 | var myPerceptron = new architect.Perceptron(2, 10, 10, 10, 10, 1); 19 | ``` 20 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/builtins/random.md: -------------------------------------------------------------------------------- 1 | description: How to use the Random model network in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: recurrent, feed-forward, gates, neural-network, random, architecture 4 | 5 | A random network is similar to a liquid network. This network will start of with a given pool of nodes, and will then create random connections between them. This network is really only useful for the initialization of the population for a genetic algorithm. 6 | 7 | ```javascript 8 | new architect.Random(input_size, hidden_size, output_size, options); 9 | ``` 10 | 11 | * `input_size` : amount of input nodes 12 | * `hidden_size` : amount of nodes inbetween input and output 13 | * `output_size` : amount of output nodes 14 | 15 | Options: 16 | * `connections` : amount of connections (default is `2 * hidden_size`, should always be bigger than `hidden_size`!) 17 | * `backconnections` : amount of recurrent connections (default is `0`) 18 | * `selfconnections` : amount of selfconnections (default is `0`) 19 | * `gates` : amount of gates (default is `0`) 20 | 21 | For example: 22 | 23 | ```javascript 24 | var network = architect.Random(1, 20, 2, { 25 | connections: 40, 26 | gates: 4, 27 | selfconnections: 4 28 | }); 29 | 30 | drawGraph(network.graph(1000, 800), '.svg'); 31 | ``` 32 | 33 | will produce: 34 | 35 | 36 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/important/important.md: -------------------------------------------------------------------------------- 1 | description: List of important functions in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: train, evolve, neataptic 4 | 5 | * [Train](train.md) 6 | * [Evolve](evolve.md) 7 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/index.md: -------------------------------------------------------------------------------- 1 | description: Welcome to the documentation of Neataptic! 2 | authors: Thomas Wagenaar 3 | keywords: machine-learning, neural-network, evolution, backpropagation 4 | 5 | Welcome to the documentation of Neataptic! If you are a rookie with neural networks: 6 | check out any of the tutorials on the left to get started. If you want more 7 | information about a certain part of Neataptic, it most probably is also in the 8 | menu on the left. If it isn't, feel free to let me know by creating an [issue](https://github.com/wagenaartje/neataptic/issues). 9 | 10 | If you want to implement a genetic neural network algorithm, but don't know how, 11 | feel free to contact me at [wagenaartje@protonmail.com](mailto:wagenaartje@protonmail.com)! 12 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/activation.md: -------------------------------------------------------------------------------- 1 | description: List of activation functions in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: activation function, squash, logistic sigmoid, neuron 4 | 5 | Activation functions determine what activation value neurons should get. Depending on your network's environment, choosing a suitable activation function can have a positive impact on the learning ability of the network. 6 | 7 | ### Methods 8 | 9 | Name | Graph | Equation | Derivative 10 | ---- | ----- | -------- | ---------- 11 | LOGISTIC | | $ f(x) = \frac{1}{1+e^{-x}} $ | $ f'(x) = f(x)(1 - f(x)) $ 12 | TANH | | $ f(x) = tanh(x) = \frac{2}{1+e^{-2x}} - 1 $ | $ f'(x) = 1 - f(x)^2 $ 13 | RELU | | $ f(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\\ x & \text{if} & x \ge 0 \end{cases} $ | $ f'(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\\ 1 & \text{if} & x \ge 0 \end{cases} $ 14 | IDENTITY | | $ f(x) = x $ | $ f'(x) = 1 $ 15 | STEP | |$ f(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\\ 1 & \text{if} & x \ge 0 \end{cases} $| $ f'(x) = \begin{cases} 0 & \text{if} & x \neq 0 \\\ ? & \text{if} & x = 0 \end{cases} $ 16 | SOFTSIGN | | $ f(x) = \frac{x}{1+\left\lvert x \right\rvert} $ | $ f'(x) = \frac{x}{{(1+\left\lvert x \right\rvert)}^2} $ 17 | SINUSOID | | $ f(x) = sin(x) $ | $ f'(x) = cos(x) $ 18 | GAUSSIAN | | $ f(x) = e^{-x^2} $ | $ f'(x) = -2xe^{-x^2} $ 19 | BENT_IDENTITY | | $ f(x) = \frac{\sqrt{x^2+1} - 1}{2} + x$ | $ f'(x) = \frac{ x }{2\sqrt{x^2+1}} + 1 $ 20 | BIPOLAR | | $ f(x) = \begin{cases} -1 & \text{if} & x \le 0 \\\ 1 & \text{if} & x \gt 0 \end{cases} $ | $ f'(x) = 0 $ 21 | BIPOLAR_SIGMOID | | $ f(x) = \frac{2}{1+e^{-x}} - 1$ | $f'(x) = \frac{(1 + f(x))(1 - f(x))}{2} $ 22 | HARD_TANH | | $ f(x) = \text{max}(-1, \text{min}(1, x)) $ | $ f'(x) = \begin{cases} 1 & \text{if} & x \gt -1 & \text{and} & x \lt 1 \\\ 0 & \text{if} & x \le -1 & \text{or} & x \ge 1 \end{cases} $ 23 | ABSOLUTE1 | | $ f(x) = \left\lvert x \right\rvert $ | $ f'(x) = \begin{cases} -1 & \text{if} & x \lt 0 \\\ 1 & \text{if} & x \ge 0 \end{cases} $ 24 | SELU | | $ f(x) = \lambda \begin{cases} x & \text{if} & x \gt 0 \\\ \alpha e^x - \alpha & \text{if} & x \le 0 \end{cases} $ | $ f'(x) = \begin{cases} \lambda & \text{if} & x \gt 0 \\\ \alpha e^x & \text{if} & x \le 0 \end{cases} $ 25 | INVERSE | | $ f(x) = 1 - x $ | $ f'(x) = -1 $ 26 | 27 | 1 avoid using this activation function on a node with a selfconnection 28 | 29 | ### Usage 30 | By default, a neuron uses a [Logistic Sigmoid](http://en.wikipedia.org/wiki/Logistic_function) as its squashing/activation function. You can change that property the following way: 31 | 32 | ```javascript 33 | var A = new Node(); 34 | A.squash = methods.activation.; 35 | 36 | // eg. 37 | A.squash = methods.activation.SINUSOID; 38 | ``` 39 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/cost.md: -------------------------------------------------------------------------------- 1 | description: List of cost functions in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: cost function, loss function, mse, cross entropy, optimize 4 | 5 | [Cost functions](https://en.wikipedia.org/wiki/Loss_functions_for_classification) 6 | play an important role in neural networks. They give neural networks an indication 7 | of 'how wrong' they are; a.k.a. how far they are from the desired output. But 8 | also in fitness functions, cost functions play an important role. 9 | 10 | ### Methods 11 | 12 | At the moment, there are 7 built-in mutation methods (all for networks): 13 | 14 | Name | Function | 15 | ---- | ------ | 16 | [methods.cost.CROSS_ENTROPY](http://neuralnetworksanddeeplearning.com/chap3.html#the_cross-entropy_cost_function) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/106c195cc961bd026ad949ad5ff89f3cde845e2c) 17 | [methods.cost.MSE](https://en.wikipedia.org/wiki/Mean_squared_error) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/67b9ac7353c6a2710e35180238efe54faf4d9c15) 18 | [methods.cost.BINARY](https://link.springer.com/referenceworkentry/10.1007%2F978-0-387-30164-8_884) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/aa1123a619eb4566439c92655d3f6331aa69c1d1) 19 | [methods.cost.MAE](https://en.wikipedia.org/wiki/Mean_absolute_error) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/3ef87b78a9af65e308cf4aa9acf6f203efbdeded) 20 | [methods.cost.MAPE](https://en.wikipedia.org/wiki/Mean_absolute_percentage_error) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/b2557e2cbee5f1cbf3c9b474878df86d1e74189a) 21 | [methods.cost.MSLE](none) | none 22 | [methods.cost.HINGE](https://en.wikipedia.org/wiki/Hinge_loss) | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/a5f42d461f1a28b27438e8f1641e042ff2e40102) 23 | 24 | ### Usage 25 | Before experimenting with any of the loss functions, note that not every loss 26 | function might 'work' for your network. Some networks have nodes with activation 27 | functions that can have negative values; this will create some weird error values 28 | with some cost methods. So if you don't know what you're doing: stick to any of 29 | the first three cost methods! 30 | 31 | 32 | ```javascript 33 | myNetwork.train(trainingData, { 34 | log: 1, 35 | iterations: 500, 36 | error: 0.03, 37 | rate: 0.05, 38 | cost: methods.cost.METHOD 39 | }); 40 | ``` 41 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/gating.md: -------------------------------------------------------------------------------- 1 | description: List of gating methods in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: gating, recurrent, LSTM, neuron, activation 4 | 5 | Gating is quite the interesting: it makes the weights in networks more dynamic, 6 | by adapting them to their gating node. Read more about it [here](https://en.wikipedia.org/wiki/Synaptic_gating). 7 | For specific implementation of gating, check out the [Node](../architecture/node.md), 8 | [Group](../architecture/group.md) and [Network](../architecture/network.md) wikis! 9 | 10 | There are 3 gating methods: 11 | 12 | * **methods.gating.OUTPUT** every node in the gating group will gate (at least) 1 node in the emitting group and all its connections to the other, receiving group 13 | * **methods.gating.INPUT** every node in the gating group will gate (at least) 1 node in the receiving group and all its connections from the other, emitting group 14 | * **methods.gating.SELF** every node in the gating group will gate (at least) 1 self connection in the emitting/receiving group 15 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/methods.md: -------------------------------------------------------------------------------- 1 | There are **a lot** of different methods for everything in Neataptic. This allows 2 | the complete customization of your networks and algorithms. If you feel like any 3 | method or function should be added, feel free to create an issue or a pull request. 4 | 5 | * [Activation](activation.md) 6 | * [Cost](cost.md) 7 | * [Gating](gating.md) 8 | * [Mutation](mutation.md) 9 | * [Regularization](regularization.md) 10 | * [Selection](selection.md) 11 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/mutation.md: -------------------------------------------------------------------------------- 1 | description: List of mutation methods in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: genetic-algorithm, mutation, modify, add, substract, genome, neural-network 4 | 5 | [Mutation](https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm)) is an important aspect of genetic algorithms. Without any mutation, there is low probability of improvement. Mutating will change the bias or weights in neural networks, changing the output of the neural network. It can have a positive, but also a negative effect on the outcome of the neural network. However, one of the [guidelines](https://en.wikipedia.org/wiki/Genetic_algorithm#Selection) of genetic algorithms is too make sure that only the positive effects will be carried on. 6 | 7 | ### Methods 8 | 9 | At the moment, there are 7 built-in mutation methods (all for networks): 10 | 11 | Name | Action | 12 | ---- | ------ | 13 | ADD_NODE | Adds a node 14 | SUB_NODE | Removes node 15 | ADD_CONN | Adds a connection between two nodes 16 | SUB_CONN | Removes a connection between two nodes 17 | MOD_WEIGHT | Modifies the weight of a connection 18 | MOD_BIAS | Modifies the bias of a node 19 | MOD_ACTIVATION | Modifies the activation function of a node 20 | ADD_SELF_CONN | Adds a self-connection to a node 21 | SUB_SELF_CONN | Removes a self-connection from a node 22 | ADD_GATE | Makes a node gate a connection 23 | SUB_GATE | Removes a gate from a connection 24 | ADD_BACK_CONN | Adds a recurrent connection 25 | SUB_BACK_CONN | Removes a recurrent connection 26 | SWAP_NODES | Swaps the bias and squash function between two nodes 27 | 28 | ### Usage 29 | All of these mutation functions can be executed on any kind of network: 30 | 31 | ```javascript 32 | myNetwork.mutate(methods.mutation.); 33 | 34 | // eg. 35 | myNetwork.mutate(methods.mutation.ADD_NODE); 36 | ``` 37 | 38 | And some on them on nodes (`MOD_BIAS` and `MOD_ACTIVATION`): 39 | 40 | ```javascript 41 | myNode.mutate(methods.mutation.); 42 | 43 | // eg. 44 | myNode.mutate(methods.mutation.MOD_BIAS); 45 | ``` 46 | 47 | For `network.evolve()` and `neat()` options, specify a list of mutation methods as follows in the options (example): 48 | 49 | ```js 50 | network.evolve(trainingset, { 51 | mutation: [methods.mutation.MOD_BIAS, methods.mutation.ADD_NODE] 52 | } 53 | ``` 54 | 55 | You can also specify groups of methods: 56 | 57 | ```js 58 | network.evolve(trainingset, { 59 | mutation: methods.mutation.ALL // all mutation methods 60 | } 61 | 62 | network.evolve(trainingset, { 63 | mutation: methods.mutation.FFW// all feedforward mutation methods 64 | } 65 | ``` 66 | 67 | # Config 68 | Some methods are configurable! You can change these config values as follows: 69 | 70 | ```js 71 | option = value; 72 | 73 | // eg. 74 | methods.mutation.MOD_ACTIVATION.mutateOutput = false; 75 | ``` 76 | 77 | Or you can edit the `methods/mutation.js` file to change the default values. 78 | 79 | ‌ 80 | 81 | ```js 82 | methods.mutation.SUB_NODE.keep_gates // default: true 83 | ``` 84 | When removing a node, you remove the connections and initialize new ones. Setting this option to true will make sure if the removed connections were gated, so will the new ones be. 85 | 86 | ‌ 87 | 88 | ```js 89 | methods.mutation.MOD_WEIGHT.min // default: -1 90 | methods.mutation.MOD_WEIGHT.max // default: 1 91 | ``` 92 | Sets the upper and lower bounds of the modification of connection weights. 93 | 94 | ‌ 95 | 96 | ```js 97 | methods.mutation.MOD_BIAS.min // default: -1 98 | methods.mutation.MOD_BIAS.max // default: 1 99 | ``` 100 | Sets the upper and lower bounds of the modification of neuron biases. 101 | 102 | ‌ 103 | 104 | ```js 105 | methods.mutation.MOD_ACTIVATION.mutateOutput // default: true 106 | methods.mutation.SWAP_NODES.mutateOutput // default: true 107 | ``` 108 | Disable this option if you want the have the activation function of the output neurons unchanged. Useful if you want to keep the output of your neural network normalized. 109 | 110 | ‌ 111 | 112 | ```js 113 | methods.mutation.MOD_ACTIVATION.allowed 114 | 115 | // default: 116 | [ 117 | activation.LOGISTIC, 118 | activation.TANH, 119 | activation.RELU, 120 | activation.IDENTITY, 121 | activation.STEP, 122 | activation.SOFTSIGN, 123 | activation.SINUSOID, 124 | activation.GAUSSIAN, 125 | activation.BENT_IDENTITY, 126 | activation.BIPOLAR, 127 | activation.BIPOLAR_SIGMOID, 128 | activation.HARD_TANH, 129 | activation.ABSOLUTE 130 | ] 131 | ``` 132 | 133 | This option allows you to specify which [activation functions](activation.md) you want to allow in your neural network. 134 | 135 | ‌ 136 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/rate.md: -------------------------------------------------------------------------------- 1 | description: A list of rate policies that can be used during the training of neural networks. 2 | authors: Thomas Wagenaar 3 | keywords: learning rate, policy, exponential, step, neural-network 4 | 5 | Rate policies allow the rate to be dynamic during the training of neural networks. 6 | A few rate policies have been built-in, but it is very easy to create your own 7 | as well. A detailed description of each rate policy is given below. 8 | 9 | You can enable a rate policy during training like this: 10 | 11 | ```javascript 12 | network.train(trainingSet, { 13 | rate: 0.3, 14 | ratePolicy: methods.rate.METHOD(options), 15 | }); 16 | ``` 17 | 18 | #### methods.rate.FIXED 19 | The default rate policy. Using this policy will make your rate static (it won't 20 | change). You do not have to specify this rate policy during training per se. 21 | 22 | #### methods.rate.STEP 23 | The rate will 'step down' every `n` iterations. 24 | 25 | ![step down rate](https://i.gyazo.com/4096f7093153d3512b28c35719aef688.png) 26 | 27 | The main usage of this policy is: 28 | 29 | ```javascript 30 | methods.rate.STEP(gamma, stepSize) 31 | 32 | // default gamma: 0.9 33 | // default stepSize: 100 34 | ``` 35 | 36 | A gamma of `0.9` means that every `stepSize` iterations, your current rate will 37 | be reduced by 10%. 38 | 39 | #### methods.rate.EXP 40 | The rate will exponentially decrease. 41 | 42 | ![exponential decrease](http://systems-sciences.uni-graz.at/etextbook/assets/img/img_sw2/decline.JPG) 43 | 44 | The main usage of this policy is: 45 | 46 | ```javascript 47 | methods.rate.EXP(gamma) 48 | 49 | // default gamma: 0.999 50 | ``` 51 | 52 | The rate at a certain iteration is calculated as: 53 | 54 | ```javascript 55 | rate = baseRate * Math.pow(gamma, iteration) 56 | ``` 57 | 58 | So a gamma of `0.999` will decrease the current rate by 0.1% every iteration 59 | 60 | #### methods.rate.INV 61 | ![reverse decay](https://i.gyazo.com/7c7a1d76f1cf3d565e20cc9b44c899a8.png) 62 | 63 | The main usage of this policy is: 64 | 65 | ```javascript 66 | methods.rate.INV(gamma, power) 67 | 68 | // default gamma: 0.001 69 | // default power: 2 70 | ``` 71 | 72 | The rate at a certain iteration is calculated as: 73 | 74 | ```javascript 75 | rate = baseRate * Math.pow(1 + gamma * iteration, -power) 76 | ``` 77 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/regularization.md: -------------------------------------------------------------------------------- 1 | description: List of regularization methods in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: regularization, dropout, neural-network, training, backpropagation, momentum 4 | 5 | Regularization helps to keep weights and/or biases small in your network. Some 6 | regularization methods also make sure that you are not overfitting your data. 7 | 8 | ### Dropout 9 | Enabling dropout will randomly set the activation of a neuron in a network to `0` 10 | with a given probability. 11 | 12 | ![](http://cs231n.github.io/assets/nn2/dropout.jpeg) 13 | 14 | Only use dropout when you are working with large datasets that may show some noise. 15 | Dropout is a method that prevents overfitting, but it shouldn't work on datasets 16 | like XOR or SINUS, as they don't have any noise. Dropout can only be used during 17 | training: 18 | 19 | ```javascript 20 | myNetwork.train(myTrainingSet, { 21 | error: 0.03, 22 | iterations: 1000, 23 | rate: 0.3, 24 | dropout: 0.4 // if you're not sure, use 0.5 25 | }); 26 | ``` 27 | 28 | Setting the dropout to `0.4` means that 40% of the neurons will be dropped out 29 | every training iteration. Please note that Neataptic has no layered network 30 | architecture, so dropout applies to the complete hidden area. 31 | 32 | ### Momentum 33 | Momentum simply adds a fraction m of the previous weight update to the current one. 34 | When the gradient keeps pointing in the same direction, this will increase the size 35 | of the steps taken towards the minimum. It is therefore often necessary to reduce 36 | the global learning rate µ when using a lot of momentum (m close to 1). 37 | If you combine a high learning rate with a lot of momentum, you will rush past the 38 | minimum with huge steps! Read more about it [here](https://www.willamette.edu/~gorr/classes/cs449/momrate.html). 39 | 40 | ![Momentum weight update equation](https://www.willamette.edu/~gorr/classes/cs449/equations/momentum.gif) 41 | 42 | you can use this option during training: 43 | 44 | ```javascript 45 | myNetwork.train(myTrainingSet, { 46 | error: 0.03, 47 | iterations: 1000, 48 | rate: 0.3, 49 | momentum: 0.9 50 | }); 51 | ``` 52 | 53 | Setting the momentum to `0.9` will mean that 90% of the previous weight change 54 | will be included in the current weight change. 55 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/methods/selection.md: -------------------------------------------------------------------------------- 1 | description: List of selection methods in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: genetic-algorithm, fitness, elitism, selection 4 | 5 | [Selection](https://en.wikipedia.org/wiki/Selection_(genetic_algorithm)) is the 6 | way in which a genetic algorithm decides which neural networks will be parents 7 | for the new generation. There are a couple of selection methods, however only a 8 | few have been integrated until now. 9 | 10 | At the moment, there are 3 built-in selection methods: 11 | 12 | Name | 13 | ---- | 14 | selection.POWER | 15 | selection.FITNESS_PROPORTIONATE | 16 | selection.TOURNAMENT | 17 | 18 | _A description on how each of these work is given below_ 19 | 20 | ### Usage 21 | You can specify your selection method while calling the `evolve()` function on a 22 | network or when constructing a new instance of the `NEAT` algorithm: 23 | 24 | ```javascript 25 | var myNetwork = new architect.Perceptron(1,1,1); 26 | var myTrainingSet = [{ input:[0], output:[1]}, { input:[1], output:[0]}]; 27 | 28 | myNetwork.evolve(myTrainingSet, { 29 | generations: 10, 30 | selection: methods.selection.POWER // eg. 31 | }); 32 | ``` 33 | 34 | Next to selection methods, `elitism` is also built in the `NEAT` constructor. 35 | [Elitism](https://en.wikipedia.org/wiki/Genetic_algorithm#Elitism) allows a 36 | genetic algorithm to pass on `n` neural networks with the highest fitness from 37 | the previous generation to the new generation, without any crossover steps in 38 | between. At the moment, elitism is only possible inside a `Neat` object. They 39 | can be passed on as follows: 40 | 41 | ```javascript 42 | var evolution = new Neat({ 43 | selection: methods.selection.FITNESS_PROPORTIONATE, 44 | elitism: 5 // amount of neural networks to keep from generation to generation 45 | }); 46 | ``` 47 | 48 | #### methods.selection.POWER 49 | When using this selection method, a random decimal value between 0 and 1 will 50 | be generated. E.g. `0.5`, then this value will get an exponential value, the 51 | default power is `4`. So `0.5**4 = 0.0625`. This will be converted into an index 52 | for the array of the current population, which is sorted from fittest to worst. 53 | 54 | **Config:** 55 | 56 | * _methods.selection.POWER.power_ : default is `4`. Increasing this value will 57 | increase the chance fitter genomes are chosen. 58 | 59 | #### methods.selection.FITNESS_PROPORTIONATE 60 | This selection method will select genomes with a probability proportionate to their fitness: 61 | 62 | ![Formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/89d0cb75150cdb5ad94ba7b168f217f9c290ee09) 63 | 64 | Read more about roulette selection [here](https://en.wikipedia.org/wiki/Fitness_proportionate_selection). 65 | 66 | #### methods.selection.TOURNAMENT 67 | This selection method will select a group of genomes from the population randomly, 68 | sort them by score, and choose the fittest individual with probability `p`, the 69 | second fittest with probability `p*(1-p)`, the third fittest with probability 70 | `p*((1-p)^2)`and so on. Read more [here](https://en.wikipedia.org/wiki/Tournament_selection). 71 | 72 | **Config:** 73 | 74 | * _methods.selection.TOURNAMENT.size_ : default is `5`. Must always be lower than 75 | the population size. A higher value will result in a population that has more 76 | equal, but fitter, parents. 77 | * _methods.selection.TOURNAMENT.probability_ : default is `0.5`. See the 78 | explanation above on how it is implemented. 79 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/tutorials/training.md: -------------------------------------------------------------------------------- 1 | description: A simple tutorial on how to get started on training neural networks with Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: training, machine-learning, neural-network, backpropagation 4 | 5 | Training your network is not that hard to do - it's the preparation that is harder. 6 | 7 | ### The training set 8 | First of all, you should normalize your data. That means you have to convert all your input and output data to values within a range of `0` to `1`. If you are unsure how to do this, visit the [Normalization](normalization.md) page. Each training sample in your training set should be an object that looks as follows: 9 | 10 | ```javascript 11 | { input: [], output: [] } 12 | ``` 13 | 14 | So an example of a training set would be (XOR): 15 | 16 | ```javascript 17 | var myTrainingSet = [ 18 | { input: [0,0], output: [0] }, 19 | { input: [0,1], output: [1] }, 20 | { input: [1,0], output: [1] }, 21 | { input: [1,1], output: [0] } 22 | ]; 23 | ``` 24 | 25 | ### The network architecture 26 | There is no fixed rule of thumb for choosing your network architecture. Adding more layers makes your neural network recognize more abstract relationships, although it requires more computation. Any function can be mapped with just one (big) hidden layer, but I do not advise this. I advise to use any of the following architectures if you're a starter: 27 | 28 | * [Perceptron](../builtins/perceptron.md) - a fully connected feed forward network 29 | * [LSTM](../builtins/lstm.md) - a recurrent network that can recognize patterns over very long time lags between inputs. 30 | * [NARX](../builtins/narx.md) - a recurrent network that remembers previous inputs and outputs 31 | 32 | But for most problems, a perceptron is sufficient. Now you only have to determine the size and amount of the network layers. I advise you to take a look at this [StackExchange question](https://stats.stackexchange.com/questions/181/how-to-choose-the-number-of-hidden-layers-and-nodes-in-a-feedforward-neural-netw) for more help on deciding the hidden size. 33 | 34 | For the training set I provided above (XOR), there are only 2 inputs and one output. I use the rule of thumb: `input size + output size = hidden size`. So the creation of my network would like this: 35 | 36 | ```javascript 37 | myNetwork = architect.Perceptron(2, 3, 1); 38 | ``` 39 | 40 | ### Training the network 41 | Finally: we're going to train the network. The function for training your network is very straight-forward: 42 | 43 | ```javascript 44 | yourNetwork.train(yourData, yourOptions); 45 | ``` 46 | 47 | There are _a lot_ of options. I won't go over all of them here, but you can check out the [Network wiki](../architecture/network.md) for all the options. 48 | 49 | I'm going to use the following options: 50 | 51 | * `log: 10` - I want to log the status every 10 iterations 52 | * `error: 0.03` - I want the training to stop if the error is below 0.03 53 | * `iterations: 1000` - I want the training to stop if the error of 0.03 hasn't been reached after 1000 iterations 54 | * `rate: 0.3` - I want a learning rate of 0.3 55 | 56 | So let's put it all together: 57 | 58 | ```javascript 59 | myNetwork.train(myTrainingSet, { 60 | log: 10, 61 | error: 0.03, 62 | iterations: 1000, 63 | rate: 0.3 64 | }); 65 | 66 | // result: {error: 0.02955628620843985, iterations: 566, time: 31} 67 | ``` 68 | 69 | Now let us check if it _actually_ works: 70 | 71 | ```javascript 72 | myNetwork.activate([0,0]); // [0.1257225731473885] 73 | myNetwork.activate([0,1]); // [0.9371910625522613] 74 | myNetwork.activate([1,0]); // [0.7770757408042104] 75 | myNetwork.activate([1,1]); // [0.1639697315652196] 76 | ``` 77 | 78 | And it works! If you want it to be more precise, lower the target error. 79 | 80 | ### Help 81 | If you need more help, feel free to create an issue [here](https://github.com/wagenaartje/neataptic/issues)! 82 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/tutorials/tutorials.md: -------------------------------------------------------------------------------- 1 | In order to get you started on Neataptic, a few tutorials have been written that 2 | give a basic overview on how to create, train and evolve your networks. It is 3 | recommended to read all of them before you start digging in your own project. 4 | 5 | * [Training](training.md) 6 | * [Evolution](evolution.md) 7 | * [Normalization](normalization.md) 8 | * [Visualization](visualization.md) 9 | 10 | If you have any questions, feel free to create an issue [here](https://github.com/wagenaartje/neataptic/issues). 11 | If you feel like anything is missing, feel free to create a pull request! 12 | -------------------------------------------------------------------------------- /mkdocs/templates/docs/tutorials/visualization.md: -------------------------------------------------------------------------------- 1 | description: A simple tutorial on how to visualize neural-networks in Neataptic 2 | authors: Thomas Wagenaar 3 | keywords: graph, model, neural-network, visualize, nodes, connections 4 | 5 | This is a step-by-step tutorial aimed to teach you how to create and visualise neural networks using Neataptic. 6 | 7 | **Step 1** 8 | Create a javascript file. Name it anything you want. But make sure to start it off with the following: 9 | 10 | ```javascript 11 | var Node = neataptic.Node; 12 | var Neat = neataptic.Neat; 13 | var Network = neataptic.Network; 14 | var Methods = neataptic.Methods; 15 | var Architect = neataptic.Architect; 16 | ``` 17 | 18 | This makes the whole developing a whole lot easier 19 | 20 | **Step 2** 21 | Create a html file. Copy and paste this template if you want: 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | ``` 43 | 44 | **Step 3** Create a network. You can do that in any of the following ways: 45 | 46 | ```javascript 47 | var network = architect.Random(2, 20, 2, 2); 48 | ``` 49 | 50 | ```javascript 51 | var network = architect.Perceptron(2, 10, 10, 2); 52 | ``` 53 | 54 | Or if you want to be more advanced, construct your own: 55 | ```javascript 56 | var A = new Node(); 57 | var B = new Node(); 58 | var C = new Node(); 59 | var D = new Node(); 60 | var E = new Node(); 61 | var F = new Node(); 62 | 63 | var nodes = [A, B, C, D, E, F]; 64 | 65 | for(var i = 0; i < nodes.length-1; i++){ 66 | node = nodes[i]; 67 | for(var j = 0; j < 2; j++){ 68 | var connectTo = nodes[Math.floor(Math.random() * (nodes.length - i) + i)]; 69 | node.connect(connectTo); 70 | } 71 | } 72 | 73 | var network = architect.Construct(nodes); 74 | ``` 75 | 76 | **Step 4** Retrieve data and draw a graph 77 | ```javascript 78 | drawGraph(network.graph(1000, 1000), '.draw'); 79 | ``` 80 | 81 | See a working example [here](https://jsfiddle.net/ch8s9d3e/30/)! 82 | See more info on graphs [here](https://github.com/wagenaartje/neataptic/tree/master/graph)! 83 | -------------------------------------------------------------------------------- /mkdocs/templates/index.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagenaartje/neataptic/ae93263ea28bb02e2dc0f3f7468cbc8814751972/mkdocs/templates/index.md -------------------------------------------------------------------------------- /mkdocs/theme/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ config.site_name }} - 404 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 62 | 63 |
64 |
65 | 66 |
67 |

404: Page not found

68 |

If something is wrong, please create an issue here!

69 |
70 |
71 |
72 | 73 | 74 | 86 | 87 | -------------------------------------------------------------------------------- /mkdocs/theme/custom.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | 5 | body { 6 | font-family: 'Roboto', sans-serif; 7 | font-size: 150%; 8 | } 9 | .brand{ 10 | color: white; 11 | font-size: 20px; 12 | font-weight: 500; 13 | letter-spacing: 1px; 14 | } 15 | .nav > ul> li { 16 | list-style-type: none; 17 | } 18 | .nav > ul> li > a { 19 | text-decoration: none; 20 | } 21 | /* navbar */ 22 | .navbar-default { 23 | background-color: #2C3963; 24 | border-bottom: 2px solid white; 25 | } 26 | /* Title */ 27 | .navbar-default .navbar-brand { 28 | color: white; 29 | } 30 | .navbar-default .navbar-brand:hover, 31 | .navbar-default .navbar-brand:focus { 32 | color: #5E5E5E; 33 | } 34 | /* Link */ 35 | .navbar-default .navbar-nav > li > a { 36 | color: rgba(255,255,255,.8); 37 | } 38 | .navbar-default .navbar-nav > li > a:hover, 39 | .navbar-default .navbar-nav > li > a:focus { 40 | color: white; 41 | } 42 | .navbar-default .navbar-nav > .active > a, 43 | .navbar-default .navbar-nav > .active > a:hover, 44 | .navbar-default .navbar-nav > .active > a:focus { 45 | color: white; 46 | background-color: #2C3963; 47 | border-bottom: 2px solid white; 48 | } 49 | 50 | /* Custom coloring */ 51 | .btn-primary{ 52 | background-color: #2C3963; 53 | border-color: #2F3D68; 54 | } 55 | 56 | .panel-warning > .panel-heading{ 57 | background-color: #2C3963; 58 | border-color: #2C3963; 59 | color: white; 60 | } 61 | .panel-warning{ 62 | border-color: #2C3963; 63 | } 64 | 65 | /* Homepage */ 66 | .jumbotron.vertical-center { 67 | margin-bottom: 0; /* Remove the default bottom margin of .jumbotron */ 68 | background-color: #2C3963; 69 | } 70 | .vertical-center { 71 | min-height: 100%; /* Fallback for vh unit */ 72 | min-height: 100vh; /* You might also want to use 73 | 'height' property instead. 74 | 75 | Note that for percentage values of 76 | 'height' or 'min-height' properties, 77 | the 'height' of the parent element 78 | should be specified explicitly. 79 | 80 | In this case the parent of '.vertical-center' 81 | is the element */ 82 | 83 | /* Make it a flex container */ 84 | display: -webkit-box; 85 | display: -moz-box; 86 | display: -ms-flexbox; 87 | display: -webkit-flex; 88 | display: flex; 89 | 90 | /* Align the bootstrap's container vertically */ 91 | -webkit-box-align : center; 92 | -webkit-align-items : center; 93 | -moz-box-align : center; 94 | -ms-flex-align : center; 95 | align-items : center; 96 | 97 | /* In legacy web browsers such as Firefox 9 98 | we need to specify the width of the flex container */ 99 | width: 100%; 100 | 101 | /* Also 'margin: 0 auto' doesn't have any effect on flex items in such web browsers 102 | hence the bootstrap's container won't be aligned to the center anymore. 103 | 104 | Therefore, we should use the following declarations to get it centered again */ 105 | -webkit-box-pack : center; 106 | -moz-box-pack : center; 107 | -ms-flex-pack : center; 108 | -webkit-justify-content : center; 109 | justify-content : center; 110 | } 111 | .welcome { 112 | color: white; 113 | } 114 | .subtitle { 115 | padding: 0; 116 | margin: 0; 117 | } 118 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/agar.ioai/field.js: -------------------------------------------------------------------------------- 1 | /* Global vars */ 2 | var players = []; 3 | var foods = []; 4 | var iteration = 0; 5 | var highestScore = 0; 6 | 7 | /** Setup the canvas */ 8 | function setup(){ 9 | var canvas = createCanvas(WIDTH, HEIGHT); 10 | canvas.parent('field'); 11 | initNeat(); 12 | 13 | // Create some food 14 | for(var i = 0; i < FOOD_AMOUNT; i++){ 15 | new Food(); 16 | } 17 | 18 | startEvaluation(); 19 | } 20 | 21 | function draw(){ 22 | clear(); 23 | squareGrid(); 24 | 25 | // Check if evaluation is done 26 | if(iteration == ITERATIONS){ 27 | endEvaluation(); 28 | iteration = 0; 29 | } 30 | 31 | // Update and visualise players 32 | for(var i = players.length - 1; i >= 0; i--){ 33 | var player = players[i]; 34 | 35 | // Some players are eaten during the iteration 36 | player.update(); 37 | player.show(); 38 | } 39 | 40 | // Update and visualise food 41 | for(var i = foods.length - 1; i >= 0; i--){ 42 | foods[i].show(); 43 | } 44 | 45 | iteration++; 46 | } 47 | 48 | /** Draw a square grid with grey lines */ 49 | function squareGrid(){ 50 | stroke(204, 204, 204, 160); 51 | fill(255); 52 | for(var x = 0; x < WIDTH/40; x++){ 53 | line(x * 40, 0, x * 40, HEIGHT); 54 | } 55 | for(var y = 0; y < HEIGHT/40; y++){ 56 | line(0, y * 40, WIDTH, y * 40); 57 | } 58 | noStroke(); 59 | } 60 | 61 | /** Calculate distance between two points */ 62 | function distance(x1, y1, x2, y2){ 63 | var dx = x1 - x2; 64 | var dy = y1 - y2; 65 | 66 | return Math.sqrt(dx * dx + dy * dy); 67 | } 68 | 69 | /** Get a relative color between red and green */ 70 | var activationColor = function(value, max){ 71 | var power = 1 - Math.min(value/max, 1); 72 | var color = [255, 255, 0] 73 | 74 | if(power < 0.5){ 75 | color[0] = 2 * power * 255; 76 | } else { 77 | color[1] = (1.0 - 2 * (power - 0.5)) * 255; 78 | } 79 | 80 | return color; 81 | } 82 | 83 | /** Get the angle from one point to another */ 84 | function angleToPoint(x1, y1, x2, y2){ 85 | d = distance(x1, y1, x2, y2); 86 | dx = (x2-x1) / d; 87 | dy = (y2-y1) / d; 88 | 89 | a = Math.acos(dx); 90 | a = dy < 0 ? 2 * Math.PI - a : a; 91 | return a; 92 | } 93 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/agar.ioai/food.js: -------------------------------------------------------------------------------- 1 | function Food(){ 2 | this.x = Math.floor(Math.random() * WIDTH); 3 | this.y = Math.floor(Math.random() * HEIGHT); 4 | this.area = FOOD_AREA; 5 | 6 | this.color = [ 7 | Math.round(Math.random() * 255), 8 | Math.round(Math.random() * 255), 9 | Math.round(Math.random() * 255) 10 | ]; 11 | 12 | foods.push(this); 13 | } 14 | 15 | Food.prototype = { 16 | /** Display the player on the field */ 17 | show: function(){ 18 | var radius = Math.sqrt(this.area / PI); 19 | 20 | fill(this.color[0], this.color[1], this.color[2]); 21 | noStroke(); 22 | ellipse(this.x, this.y, radius); 23 | }, 24 | 25 | /** Restart from new position */ 26 | restart: function(){ 27 | this.x = Math.floor(Math.random() * WIDTH); 28 | this.y = Math.floor(Math.random() * HEIGHT); 29 | }, 30 | 31 | }; 32 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/agar.ioai/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"}, 4 | { type: 'script', url: "../../js/articles/agar.ioai/main.js"}, 5 | { type: 'script', url: "../../js/articles/agar.ioai/population.js"}, 6 | { type: 'script', url: "../../js/articles/agar.ioai/player.js"}, 7 | { type: 'script', url: "../../js/articles/agar.ioai/food.js"}, 8 | { type: 'script', url: "../../js/articles/agar.ioai/field.js"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.rel = 'stylesheet'; 23 | stylesheet.type = 'text/css'; 24 | stylesheet.href = link.url; 25 | stylesheet.media = "screen,print"; 26 | document.head.appendChild(stylesheet); 27 | } 28 | }); 29 | } 30 | loadScript(list.shift()).then(function() { 31 | if (list.length > 0) { 32 | require(list); 33 | } 34 | }) 35 | } 36 | 37 | require(scripts); 38 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/agar.ioai/main.js: -------------------------------------------------------------------------------- 1 | /** Rename vars */ 2 | var Neat = neataptic.Neat; 3 | var Methods = neataptic.Methods; 4 | var Config = neataptic.Config; 5 | var Architect = neataptic.Architect; 6 | 7 | /** Turn off warnings */ 8 | Config.warnings = false; 9 | 10 | /** Settings */ 11 | var WIDTH = $('#field').width(); 12 | var HEIGHT = 500; 13 | 14 | var MAX_AREA = 10000; 15 | var MIN_AREA = 400; 16 | 17 | var RELATIVE_SIZE = 1.1; 18 | var DECREASE_SIZE = 0.998; 19 | 20 | var DETECTION_RADIUS = 150; 21 | var FOOD_DETECTION = 3; 22 | var PLAYER_DETECTION = 3; 23 | 24 | var MIN_SPEED = 0.6; 25 | var SPEED = 2; 26 | 27 | var FOOD_AREA = 80; 28 | var FOOD_AMOUNT = Math.round(WIDTH * HEIGHT * 4e-4); 29 | 30 | // GA settings 31 | var PLAYER_AMOUNT = Math.round(WIDTH * HEIGHT * 8e-5); 32 | var ITERATIONS = 10e10; 33 | var START_HIDDEN_SIZE = 0; 34 | 35 | // Trained population 36 | var USE_TRAINED_POP = true; 37 | 38 | // Global vars 39 | var neat; 40 | 41 | /** Construct the genetic algorithm */ 42 | function initNeat(){ 43 | neat = new Neat( 44 | 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, 45 | 2, 46 | null, 47 | { 48 | mutation: [ 49 | Methods.Mutation.ADD_NODE, 50 | Methods.Mutation.SUB_NODE, 51 | Methods.Mutation.ADD_CONN, 52 | Methods.Mutation.SUB_CONN, 53 | Methods.Mutation.MOD_WEIGHT, 54 | Methods.Mutation.MOD_BIAS, 55 | Methods.Mutation.MOD_ACTIVATION, 56 | Methods.Mutation.ADD_GATE, 57 | Methods.Mutation.SUB_GATE, 58 | Methods.Mutation.ADD_SELF_CONN, 59 | Methods.Mutation.SUB_SELF_CONN, 60 | Methods.Mutation.ADD_BACK_CONN, 61 | Methods.Mutation.SUB_BACK_CONN 62 | ], 63 | popsize: PLAYER_AMOUNT, 64 | mutationRate: 0.3, 65 | elitism: Math.round(0.1 * PLAYER_AMOUNT), 66 | network: new Architect.Random( 67 | 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, 68 | START_HIDDEN_SIZE, 69 | 2 70 | ) 71 | } 72 | ); 73 | 74 | if(USE_TRAINED_POP){ 75 | neat.population = population; 76 | } 77 | } 78 | 79 | /** Start the evaluation of the current generation */ 80 | function startEvaluation(){ 81 | players = []; 82 | highestScore = 0; 83 | 84 | for(var genome in neat.population){ 85 | genome = neat.population[genome]; 86 | new Player(genome); 87 | } 88 | } 89 | 90 | /** End the evaluation of the current generation */ 91 | function endEvaluation(){ 92 | console.log('Generation:', neat.generation, '- average score:', neat.getAverage()); 93 | 94 | neat.sort(); 95 | var newPopulation = []; 96 | 97 | // Elitism 98 | for(var i = 0; i < neat.elitism; i++){ 99 | newPopulation.push(neat.population[i]); 100 | } 101 | 102 | // Breed the next individuals 103 | for(var i = 0; i < neat.popsize - neat.elitism; i++){ 104 | newPopulation.push(neat.getOffspring()); 105 | } 106 | 107 | // Replace the old population with the new population 108 | neat.population = newPopulation; 109 | neat.mutate(); 110 | 111 | neat.generation++; 112 | startEvaluation(); 113 | } 114 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/classifycolors/custom.css: -------------------------------------------------------------------------------- 1 | #circle { 2 | width: 20px; 3 | height: 20px; 4 | -webkit-border-radius: 10px; 5 | -moz-border-radius: 10px; 6 | border-radius: 10px; 7 | display: inline-block; 8 | } 9 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/classifycolors/events.js: -------------------------------------------------------------------------------- 1 | $('.colors').change(function(){ 2 | var color = $(this).attr('value'); 3 | if($(this).is(":checked")) { 4 | COLORS.push(color); 5 | } else { 6 | COLORS.splice(COLORS.indexOf(color), 1); 7 | } 8 | 9 | set = createSet(); 10 | visualiseSet(); 11 | }); 12 | $('.start').click(function(e){ 13 | e.preventDefault(); 14 | if(running == false){ 15 | running = true; 16 | iteration = 0; 17 | createNeat(); 18 | $(this).html(' Stop evolution'); 19 | setTimeout(loop, 1); 20 | } else { 21 | running = false; 22 | $(this).html(' Start evolution'); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/classifycolors/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js" }, 3 | { type: 'script', url: "../../js/articles/classifycolors/events.js" }, 4 | { type: 'script', url: "../../js/articles/classifycolors/randomColor.js" }, 5 | { type: 'script', url: "../../js/articles/classifycolors/neural.js" }, 6 | { type: 'css', url: "../../js/articles/classifycolors/custom.css"} 7 | ]; 8 | 9 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 10 | function require(list) { 11 | function loadScript(link) { 12 | return new Promise(function(fulfill, reject) { 13 | if(link.type == 'script'){ 14 | var script = document.createElement("script"); 15 | script.addEventListener("load", fulfill); 16 | script.src = link.url; 17 | document.head.appendChild(script); 18 | } else if(link.type == 'css'){ 19 | var stylesheet = document.createElement('link'); 20 | stylesheet.rel = 'stylesheet'; 21 | stylesheet.type = 'text/css'; 22 | stylesheet.href = link.url; 23 | stylesheet.media = "screen,print"; 24 | document.head.appendChild(stylesheet); 25 | } 26 | }); 27 | } 28 | loadScript(list.shift()).then(function() { 29 | if (list.length > 0) { 30 | require(list); 31 | } 32 | }) 33 | } 34 | 35 | require(scripts); 36 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/classifycolors/neural.js: -------------------------------------------------------------------------------- 1 | var Neat = neataptic.Neat; 2 | var Methods = neataptic.Methods; 3 | var Network = neataptic.Network; 4 | 5 | var set; 6 | var neat; 7 | var running = false; 8 | var iteration = 0; 9 | 10 | var PER_COLOR = 50; 11 | // Possible colors: red, orange, yellow, green, blue, purple, pink and monochrome 12 | var COLORS = ['red', 'green', 'blue']; 13 | var network; 14 | 15 | $( document ).ready(function(){ 16 | set = createSet(); 17 | visualiseSet(); 18 | }); 19 | 20 | function createNeat(){ 21 | network = new Network(3, COLORS.length); 22 | /*neat = new Neat(3, COLORS.length, fitness, { 23 | mutation: [ 24 | Methods.Mutation.ADD_NODE, 25 | Methods.Mutation.ADD_CONN, 26 | Methods.Mutation.MOD_WEIGHT, 27 | Methods.Mutation.MOD_BIAS, 28 | Methods.Mutation.SUB_NODE, 29 | Methods.Mutation.MOD_ACTIVATION 30 | ], 31 | mutationRate: 0.6, 32 | elitism: 5, 33 | popsize: 100, 34 | });*/ 35 | } 36 | 37 | function visualiseSet(){ 38 | $('.set').empty(); 39 | for(color in COLORS){ 40 | $('.set').append('

' + COLORS[color] + '

'); 41 | } 42 | 43 | for(var item in set){ 44 | item = set[item]; 45 | $('.'+ item.color).append('
'); 46 | } 47 | } 48 | 49 | function visualiseGenomeSet(genome){ 50 | $('.fittestset').empty(); 51 | for(color in COLORS){ 52 | $('.fittestset').append('

' + COLORS[color] + '

'); 53 | } 54 | 55 | for(var item in set){ 56 | item = set[item]; 57 | var output = genome.activate(item.input); 58 | var max = Math.max.apply(null, output); 59 | var color = COLORS[output.indexOf(max)]; 60 | 61 | $('.fittest'+ color).append('
'); 62 | } 63 | } 64 | 65 | function loop(){ 66 | network.evolve(set, { 67 | iterations: 1, 68 | mutationRate: 0.6, 69 | elisitm: 5, 70 | popSize: 100, 71 | mutation: Methods.Mutation.FFW, 72 | cost: Methods.Cost.MSE 73 | }); 74 | 75 | visualiseGenomeSet(network); 76 | 77 | $('.iteration').text(iteration); 78 | $('.bestfitness').text(network.test(set).error); 79 | 80 | iteration++; 81 | if(running) setTimeout(loop, 1); 82 | } 83 | 84 | // Thanks to https://github.com/davidmerfield/randomColor !! 85 | function createSet(){ 86 | var set = []; 87 | 88 | for(index in COLORS){ 89 | var color = COLORS[index]; 90 | 91 | var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'}); 92 | 93 | for(var random in randomColors){ 94 | var rgb = randomColors[random]; 95 | random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(','); 96 | for(var y in random) random[y] = random[y]/255; 97 | 98 | var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0); 99 | output[index] = 1; 100 | 101 | set.push({ input: random, output: output, color: color, rgb: rgb}); 102 | } 103 | } 104 | 105 | return set; 106 | } 107 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/neuroevolution/events.js: -------------------------------------------------------------------------------- 1 | $(document).on('click', '.panel div.clickable', function (e) { 2 | var $this = $(this); //Heading 3 | var $panel = $this.parent('.panel'); 4 | var $panel_body = $panel.children('.panel-body'); 5 | var $display = $panel_body.css('display'); 6 | 7 | if ($display == 'block') { 8 | $panel_body.slideUp(); 9 | } else if($display == 'none') { 10 | $panel_body.slideDown(); 11 | } 12 | }); 13 | 14 | $(document).ready(function(e){ 15 | var $classy = '.panel.autocollapse'; 16 | 17 | var $found = $($classy); 18 | $found.find('.panel-body').hide(); 19 | $found.removeClass($classy); 20 | }); 21 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/neuroevolution/graph.css: -------------------------------------------------------------------------------- 1 | .node { 2 | cursor: move; 3 | stroke-width: 1.5px; 4 | } 5 | .link { 6 | fill: none; 7 | stroke: #BDBDBD; 8 | stroke-width: 1.5px; 9 | opacity: 0.4; 10 | marker-end: url(#end-arrow); 11 | } 12 | .label { 13 | fill: #CCCCCC; 14 | font-size: 9px; 15 | text-anchor: middle; 16 | cursor: move; 17 | font-family: Arial; 18 | } 19 | #end-arrow{ 20 | opacity: 0.4; 21 | } 22 | .INPUT{ 23 | fill: #ff6666; 24 | stroke: #ff4d4d; 25 | } 26 | .OUTPUT{ 27 | fill : #ff8c66; 28 | stroke: #ff794d; 29 | } 30 | .LOGISTIC{ 31 | fill: #ffb366; 32 | stroke: #ffa64d; 33 | } 34 | .TANH{ 35 | fill: #ffd966; 36 | stroke: #ffd24d; 37 | } 38 | .IDENTITY{ 39 | fill: #ffff66; 40 | stroke: #ffff4d; 41 | } 42 | .STEP{ 43 | fill: #d9ff66; 44 | stroke: #d2ff4d; 45 | } 46 | .RELU{ 47 | fill: #b3ff66; 48 | stroke: #a6ff4d; 49 | } 50 | .SOFTSIGN{ 51 | fill: #8cff66; 52 | stroke: #79ff4d; 53 | } 54 | .SINUSOID{ 55 | fill: #66ff66; 56 | stroke: #4dff4d; 57 | } 58 | .GAUSSIAN{ 59 | fill: #66ff8c; 60 | stroke: #4dff79; 61 | } 62 | .BENT_IDENTITY{ 63 | fill: #66ffd9; 64 | stroke: #4dffd2; 65 | } 66 | .BIPOLAR{ 67 | fill: #66d9ff; 68 | stroke: #4dd2ff; 69 | } 70 | .BIPOLAR_SIGMOID{ 71 | fill: #66b3ff; 72 | stroke: #4da6ff; 73 | } 74 | .HARD_TANH{ 75 | fill: #668cff; 76 | stroke: #4d79ff; 77 | } 78 | .ABSOLUTE{ 79 | fill: #6666ff; 80 | stroke: #4d4dff; 81 | } 82 | .GATE{ 83 | fill: #003300; 84 | stroke: #001a00; 85 | } 86 | .CONSTANT{ 87 | fill: #ff00ff; 88 | stroke: #e600e6; 89 | } 90 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/neuroevolution/graph.js: -------------------------------------------------------------------------------- 1 | var NODE_RADIUS = 7; 2 | var REPEL_FORCE = 0; 3 | var LINK_DISTANCE = 100; 4 | 5 | var drawGraph = function(graph, panel, width, height) { 6 | var d3cola = cola.d3adaptor() 7 | .avoidOverlaps(true) 8 | .size([width, height]); 9 | 10 | var svg = d3.select(panel); 11 | 12 | d3.selectAll(panel + "> *").remove(); 13 | 14 | // define arrow markers for graph links 15 | svg.append('svg:defs').append('svg:marker') 16 | .attr('id', 'end-arrow') 17 | .attr('viewBox', '0 -5 10 10') 18 | .attr('refX', 6) 19 | .attr('markerWidth', 4) 20 | .attr('markerHeight', 4) 21 | .attr('orient', 'auto') 22 | .append('svg:path') 23 | .attr('d', 'M0,-5L10,0L0,5') 24 | 25 | graph.nodes.forEach(function (v) { v.height = v.width = 2 * NODE_RADIUS; }); 26 | 27 | d3cola 28 | .nodes(graph.nodes) 29 | .links(graph.links) 30 | //.constraints(graph.constraints) 31 | .symmetricDiffLinkLengths(REPEL_FORCE) 32 | .linkDistance(LINK_DISTANCE) 33 | .start(10, 15, 20); 34 | 35 | var path = svg.selectAll(".link") 36 | .data(graph.links) 37 | .enter().append('svg:path') 38 | .attr('class', 'link') 39 | 40 | path.append("title") 41 | .text(function (d) { 42 | var text = ""; 43 | text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";; 44 | text += "Source: " + d.source.id + "\n";; 45 | text += "Target: " + d.target.id; 46 | return text; 47 | }); 48 | 49 | var node = svg.selectAll(".node") 50 | .data(graph.nodes) 51 | .enter().append("circle") 52 | .attr("class", function(d){ 53 | return "node " + d.name; 54 | }) 55 | .attr("r", function(d) { return NODE_RADIUS; }) 56 | 57 | .call(d3cola.drag); 58 | 59 | node.append("title") 60 | .text(function (d){ 61 | var text = ""; 62 | text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n"; 63 | text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n"; 64 | text += "Position: " + d.id; 65 | return text; 66 | }); 67 | 68 | var label = svg.selectAll(".label") 69 | .data(graph.nodes) 70 | .enter().append("text") 71 | .attr("class", "label") 72 | .text(function (d){return '(' + d.index + ') ' + d.name; }) 73 | .call(d3cola.drag) 74 | 75 | d3cola.on("tick", function () { 76 | // draw directed edges with proper padding from node centers 77 | path.attr('d', function (d) { 78 | var deltaX = d.target.x - d.source.x, 79 | deltaY = d.target.y - d.source.y, 80 | dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), 81 | normX = deltaX / dist, 82 | normY = deltaY / dist; 83 | 84 | if(isNaN(normX)) normX = 0; 85 | if(isNaN(normY)) normY = 0; 86 | 87 | sourcePadding = NODE_RADIUS, 88 | targetPadding = NODE_RADIUS + 2, 89 | sourceX = d.source.x + (sourcePadding * normX), 90 | sourceY = d.source.y + (sourcePadding * normY), 91 | targetX = d.target.x - (targetPadding * normX), 92 | targetY = d.target.y - (targetPadding * normY); 93 | 94 | // Defaults for normal edge. 95 | drx = 0, 96 | dry = 0, 97 | xRotation = 0, // degrees 98 | largeArc = 0, // 1 or 0 99 | sweep = 1; // 1 or 0 100 | 101 | // Self edge. 102 | if (d.source.x === d.target.x && d.source.y === d.target.y) { 103 | drx = dist; 104 | dry = dist; 105 | xRotation = -45; 106 | largeArc = 1; 107 | drx = 20; 108 | dry = 20; 109 | targetX = targetX + 1; 110 | targetY = targetY + 1; 111 | } 112 | return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY; 113 | }); 114 | 115 | node.attr("cx", function (d) { return d.x; }) 116 | .attr("cy", function (d) { return d.y; }) 117 | 118 | label 119 | .attr("x", function (d) { return d.x + 10; }) 120 | .attr("y", function (d) { return d.y - 10; }); 121 | }); 122 | }; 123 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/neuroevolution/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"}, 4 | { type: 'script', url: "../../js/articles/neuroevolution/webcola.js"}, 5 | { type: 'script', url: "../../js/articles/neuroevolution/events.js"}, 6 | { type: 'script', url: "../../js/articles/neuroevolution/graph.js"}, 7 | { type: 'script', url: "../../js/articles/neuroevolution/neural.js"}, 8 | { type: 'css', url: "../../js/articles/neuroevolution/graph.css"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.addEventListener("load", fulfill); 23 | stylesheet.rel = 'stylesheet'; 24 | stylesheet.type = 'text/css'; 25 | stylesheet.href = link.url; 26 | stylesheet.media = "screen,print"; 27 | document.head.appendChild(stylesheet); 28 | } 29 | }); 30 | } 31 | loadScript(list.shift()).then(function() { 32 | if (list.length > 0) { 33 | require(list); 34 | } 35 | }) 36 | } 37 | 38 | require(scripts); 39 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/playground/events.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() { 2 | $( ".start" ).click(function() { 3 | $( ".start" ).html(' Running...'); 4 | newNeat(); 5 | loop(); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/playground/extra.css: -------------------------------------------------------------------------------- 1 | .btn-group, .input-group, pre{ 2 | margin-top: 10px; 3 | } 4 | .node { 5 | cursor: move; 6 | stroke-width: 1.5px; 7 | } 8 | .link { 9 | fill: none; 10 | stroke: #BDBDBD; 11 | stroke-width: 1.5px; 12 | opacity: 0.4; 13 | marker-end: url(#end-arrow); 14 | } 15 | .label { 16 | fill: #CCCCCC; 17 | font-size: 9px; 18 | text-anchor: middle; 19 | cursor: move; 20 | font-family: Arial; 21 | } 22 | #end-arrow{ 23 | opacity: 0.4; 24 | } 25 | .INPUT{ 26 | fill: #ff6666; 27 | stroke: #ff4d4d; 28 | } 29 | .OUTPUT{ 30 | fill : #ff8c66; 31 | stroke: #ff794d; 32 | } 33 | .LOGISTIC{ 34 | fill: #ffb366; 35 | stroke: #ffa64d; 36 | } 37 | .TANH{ 38 | fill: #ffd966; 39 | stroke: #ffd24d; 40 | } 41 | .IDENTITY{ 42 | fill: #ffff66; 43 | stroke: #ffff4d; 44 | } 45 | .STEP{ 46 | fill: #d9ff66; 47 | stroke: #d2ff4d; 48 | } 49 | .RELU{ 50 | fill: #b3ff66; 51 | stroke: #a6ff4d; 52 | } 53 | .SOFTSIGN{ 54 | fill: #8cff66; 55 | stroke: #79ff4d; 56 | } 57 | .SINUSOID{ 58 | fill: #66ff66; 59 | stroke: #4dff4d; 60 | } 61 | .GAUSSIAN{ 62 | fill: #66ff8c; 63 | stroke: #4dff79; 64 | } 65 | .BENT_IDENTITY{ 66 | fill: #66ffd9; 67 | stroke: #4dffd2; 68 | } 69 | .BIPOLAR{ 70 | fill: #66d9ff; 71 | stroke: #4dd2ff; 72 | } 73 | .BIPOLAR_SIGMOID{ 74 | fill: #66b3ff; 75 | stroke: #4da6ff; 76 | } 77 | .HARD_TANH{ 78 | fill: #668cff; 79 | stroke: #4d79ff; 80 | } 81 | .ABSOLUTE{ 82 | fill: #6666ff; 83 | stroke: #4d4dff; 84 | } 85 | .GATE{ 86 | fill: #003300; 87 | stroke: #001a00; 88 | } 89 | .CONSTANT{ 90 | fill: #ff00ff; 91 | stroke: #e600e6; 92 | } 93 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/playground/graph.js: -------------------------------------------------------------------------------- 1 | var NODE_RADIUS = 7; 2 | var GATE_RADIUS = 2; 3 | var REPEL_FORCE = 0; 4 | var LINK_DISTANCE = 100; 5 | 6 | var WIDTH = 500; 7 | var HEIGHT = 600; 8 | 9 | var d3cola = cola.d3adaptor() 10 | .avoidOverlaps(true) 11 | .size([WIDTH, HEIGHT]); 12 | 13 | var drawGraph = function(graph, panel) { 14 | var svg = d3.select(panel); 15 | 16 | d3.selectAll(panel + "> *").remove(); 17 | 18 | // define arrow markers for graph links 19 | svg.append('svg:defs').append('svg:marker') 20 | .attr('id', 'end-arrow') 21 | .attr('viewBox', '0 -5 10 10') 22 | .attr('refX', 6) 23 | .attr('markerWidth', 4) 24 | .attr('markerHeight', 4) 25 | .attr('orient', 'auto') 26 | .append('svg:path') 27 | .attr('d', 'M0,-5L10,0L0,5') 28 | 29 | graph.nodes.forEach(function(v){ 30 | v.height = v.width = 2 * (v.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS); } 31 | ); 32 | 33 | d3cola 34 | .nodes(graph.nodes) 35 | .links(graph.links) 36 | .constraints(graph.constraints) 37 | .symmetricDiffLinkLengths(REPEL_FORCE) 38 | .linkDistance(LINK_DISTANCE) 39 | .start(10, 15, 20); 40 | 41 | var path = svg.selectAll(".link") 42 | .data(graph.links) 43 | .enter().append('svg:path') 44 | .attr('class', 'link') 45 | 46 | path.append("title") 47 | .text(function (d) { 48 | var text = ""; 49 | text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";; 50 | text += "Source: " + d.source.id + "\n";; 51 | text += "Target: " + d.target.id; 52 | return text; 53 | }); 54 | 55 | var node = svg.selectAll(".node") 56 | .data(graph.nodes) 57 | .enter().append("circle") 58 | .attr("class", function(d){ 59 | return "node " + d.name; 60 | }) 61 | .attr("r", function(d) { return d.name == 'GATE' ? GATE_RADIUS : NODE_RADIUS; }) 62 | 63 | .call(d3cola.drag); 64 | 65 | node.append("title") 66 | .text(function (d){ 67 | var text = ""; 68 | text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n"; 69 | text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n"; 70 | text += "Position: " + d.id; 71 | return text; 72 | }); 73 | 74 | var label = svg.selectAll(".label") 75 | .data(graph.nodes) 76 | .enter().append("text") 77 | .attr("class", "label") 78 | .text(function (d){return '(' + d.index + ') ' + d.name; }) 79 | .call(d3cola.drag) 80 | 81 | d3cola.on("tick", function () { 82 | // draw directed edges with proper padding from node centers 83 | path.attr('d', function (d) { 84 | var deltaX = d.target.x - d.source.x, 85 | deltaY = d.target.y - d.source.y, 86 | dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), 87 | normX = deltaX / dist, 88 | normY = deltaY / dist; 89 | 90 | if(isNaN(normX)) normX = 0; 91 | if(isNaN(normY)) normY = 0; 92 | 93 | sourcePadding = d.source.width / 2, 94 | targetPadding = d.target.width / 2 + 2, 95 | sourceX = d.source.x + (sourcePadding * normX), 96 | sourceY = d.source.y + (sourcePadding * normY), 97 | targetX = d.target.x - (targetPadding * normX), 98 | targetY = d.target.y - (targetPadding * normY); 99 | 100 | // Defaults for normal edge. 101 | drx = 0, 102 | dry = 0, 103 | xRotation = 0, // degrees 104 | largeArc = 0, // 1 or 0 105 | sweep = 1; // 1 or 0 106 | 107 | // Self edge. 108 | if (d.source.x === d.target.x && d.source.y === d.target.y) { 109 | drx = dist; 110 | dry = dist; 111 | xRotation = -45; 112 | largeArc = 1; 113 | drx = 20; 114 | dry = 20; 115 | targetX = targetX + 1; 116 | targetY = targetY + 1; 117 | } 118 | return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY; 119 | }); 120 | 121 | node.attr("cx", function (d) { return d.x; }) 122 | .attr("cy", function (d) { return d.y; }) 123 | 124 | label 125 | .attr("x", function (d) { return d.x + 10; }) 126 | .attr("y", function (d) { return d.y - 10; }); 127 | }); 128 | }; 129 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/playground/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.3.4/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"}, 4 | { type: 'script', url: "../../js/articles/neuroevolution/webcola.js"}, 5 | { type: 'script', url: "../../js/articles/playground/events.js"}, 6 | { type: 'script', url: "../../js/articles/playground/graph.js"}, 7 | { type: 'script', url: "../../js/articles/playground/neural.js"}, 8 | { type: 'css', url: "../../js/articles/playground/extra.css"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.addEventListener("load", fulfill); 23 | stylesheet.rel = 'stylesheet'; 24 | stylesheet.type = 'text/css'; 25 | stylesheet.href = link.url; 26 | stylesheet.media = "screen,print"; 27 | document.head.appendChild(stylesheet); 28 | } 29 | }); 30 | } 31 | loadScript(list.shift()).then(function() { 32 | if (list.length > 0) { 33 | require(list); 34 | } 35 | }) 36 | } 37 | 38 | require(scripts); 39 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/playground/neural.js: -------------------------------------------------------------------------------- 1 | var { Network, methods, architect } = neataptic; 2 | 3 | var network = new Network(2, 1); 4 | $(document).ready(function () { 5 | refresh(); 6 | activate(); 7 | }); 8 | 9 | function mutate (method) { 10 | network.mutate(method); 11 | refresh(); 12 | activate(); 13 | } 14 | 15 | function activate () { 16 | var in1 = $('.input1').val(); 17 | var in2 = $('.input2').val(); 18 | 19 | if(in1 > 1 || in1 < 0 || in2 > 1 || in2 < 0){ 20 | alert('Inputs must be between 0 and 1!'); 21 | } 22 | 23 | var output = network.activate([in1, in2]); 24 | $('.output').text(output); 25 | } 26 | function refresh(){ 27 | drawGraph(network.graph($('.draw').width() / 1.4, $('.draw').height() / 1.4), '.draw'); 28 | } 29 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/target-seekingai/field.js: -------------------------------------------------------------------------------- 1 | /* Global vars */ 2 | var players = []; 3 | var walker = new Walker(); 4 | var iteration = 0; 5 | var highestScore = 0; 6 | 7 | /** Setup the canvas */ 8 | function setup(){ 9 | var canvas = createCanvas(WIDTH, HEIGHT); 10 | canvas.parent('field'); 11 | initNeat(); 12 | 13 | // Do some initial mutation 14 | if(!USE_TRAINED_POP){ 15 | for(var i = 0; i < 1; i++) neat.mutate(); 16 | } 17 | 18 | startEvaluation(); 19 | } 20 | 21 | function draw(){ 22 | clear(); 23 | squareGrid(); 24 | 25 | // Check if evaluation is done 26 | if(iteration == ITERATIONS){ 27 | endEvaluation(); 28 | iteration = 0; 29 | } 30 | 31 | // Update and visualise players 32 | for(var i = players.length - 1; i >= 0; i--){ 33 | var player = players[i]; 34 | 35 | // Some players are eaten during the iteration 36 | player.update(); 37 | player.show(); 38 | } 39 | 40 | walker.update(); 41 | walker.show(); 42 | 43 | iteration++; 44 | } 45 | 46 | /** Draw a square grid with grey lines */ 47 | function squareGrid(){ 48 | stroke(204, 204, 204, 160); 49 | strokeWeight(1); 50 | fill(255); 51 | for(var x = 0; x < WIDTH/40; x++){ 52 | line(x * 40, 0, x * 40, HEIGHT); 53 | } 54 | for(var y = 0; y < HEIGHT/40; y++){ 55 | line(0, y * 40, WIDTH, y * 40); 56 | } 57 | noStroke(); 58 | } 59 | 60 | /** Calculate distance between two points */ 61 | function distance(x1, y1, x2, y2){ 62 | var dx = x1 - x2; 63 | var dy = y1 - y2; 64 | 65 | return Math.sqrt(dx * dx + dy * dy); 66 | } 67 | 68 | /** Get a relative color between red and green */ 69 | var activationColor = function(value, max){ 70 | var power = 1 - Math.min(value/max, 1); 71 | var color = [255, 255, 0] 72 | 73 | if(power < 0.5){ 74 | color[0] = 2 * power * 255; 75 | } else { 76 | color[1] = (1.0 - 2 * (power - 0.5)) * 255; 77 | } 78 | 79 | return color; 80 | } 81 | 82 | /** Get the angle from one point to another */ 83 | function angleToPoint(x1, y1, x2, y2){ 84 | d = distance(x1, y1, x2, y2); 85 | dx = (x2-x1) / d; 86 | dy = (y2-y1) / d; 87 | 88 | a = Math.acos(dx); 89 | a = dy < 0 ? 2 * Math.PI - a : a; 90 | return a; 91 | } 92 | 93 | /** Set the walker to a new location */ 94 | function mouseClicked(){ 95 | if(mouseX >= 0 && mouseX <= WIDTH && mouseY >= 0 && mouseY <= HEIGHT){ 96 | walker.x = mouseX; 97 | walker.y = mouseY; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/target-seekingai/import.js: -------------------------------------------------------------------------------- 1 | var scripts = [ 2 | { type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"}, 3 | { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"}, 4 | { type: 'script', url: "../../js/articles/target-seekingai/main.js"}, 5 | { type: 'script', url: "../../js/articles/target-seekingai/population.js"}, 6 | { type: 'script', url: "../../js/articles/target-seekingai/player.js"}, 7 | { type: 'script', url: "../../js/articles/target-seekingai/walker.js"}, 8 | { type: 'script', url: "../../js/articles/target-seekingai/field.js"} 9 | ]; 10 | 11 | /** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ 12 | function require(list) { 13 | function loadScript(link) { 14 | return new Promise(function(fulfill, reject) { 15 | if(link.type == 'script'){ 16 | var script = document.createElement("script"); 17 | script.addEventListener("load", fulfill); 18 | script.src = link.url; 19 | document.head.appendChild(script); 20 | } else if(link.type == 'css'){ 21 | var stylesheet = document.createElement('link'); 22 | stylesheet.rel = 'stylesheet'; 23 | stylesheet.type = 'text/css'; 24 | stylesheet.href = link.url; 25 | stylesheet.media = "screen,print"; 26 | document.head.appendChild(stylesheet); 27 | } 28 | }); 29 | } 30 | loadScript(list.shift()).then(function() { 31 | if (list.length > 0) { 32 | require(list); 33 | } 34 | }) 35 | } 36 | 37 | require(scripts); 38 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/target-seekingai/main.js: -------------------------------------------------------------------------------- 1 | /** Rename vars */ 2 | var Neat = neataptic.Neat; 3 | var Methods = neataptic.Methods; 4 | var Config = neataptic.Config; 5 | var Architect = neataptic.Architect; 6 | 7 | /** Turn off warnings */ 8 | Config.warnings = false; 9 | 10 | /** Settings */ 11 | var WIDTH = $('#field').width(); 12 | var HEIGHT = 500; 13 | var MAX_SPEED = 5; 14 | var START_X = WIDTH/2; 15 | var START_Y = HEIGHT/2; 16 | var SCORE_RADIUS = 100; 17 | 18 | // GA settings 19 | var PLAYER_AMOUNT = Math.round(2.3e-4 * WIDTH * HEIGHT); 20 | var ITERATIONS = 10e6; // should be ~250 for real use 21 | var MUTATION_RATE = 0.3; 22 | var ELITISM = Math.round(0.1 * PLAYER_AMOUNT); 23 | 24 | // Trained population 25 | var USE_TRAINED_POP = true; 26 | 27 | /** Global vars */ 28 | var neat; 29 | 30 | /** Construct the genetic algorithm */ 31 | function initNeat(){ 32 | neat = new Neat( 33 | 6, 1, 34 | null, 35 | { 36 | mutation: [ 37 | Methods.Mutation.ADD_NODE, 38 | Methods.Mutation.SUB_NODE, 39 | Methods.Mutation.ADD_CONN, 40 | Methods.Mutation.SUB_CONN, 41 | Methods.Mutation.MOD_WEIGHT, 42 | Methods.Mutation.MOD_BIAS, 43 | Methods.Mutation.MOD_ACTIVATION, 44 | Methods.Mutation.ADD_GATE, 45 | Methods.Mutation.SUB_GATE, 46 | Methods.Mutation.ADD_SELF_CONN, 47 | Methods.Mutation.SUB_SELF_CONN, 48 | Methods.Mutation.ADD_BACK_CONN, 49 | Methods.Mutation.SUB_BACK_CONN 50 | ], 51 | popsize: PLAYER_AMOUNT, 52 | mutationRate: MUTATION_RATE, 53 | elitism: ELITISM 54 | } 55 | ); 56 | 57 | if(USE_TRAINED_POP){ 58 | neat.population = population; 59 | } 60 | } 61 | 62 | /** Start the evaluation of the current generation */ 63 | function startEvaluation(){ 64 | players = []; 65 | highestScore = 0; 66 | 67 | for(var genome in neat.population){ 68 | genome = neat.population[genome]; 69 | new Player(genome); 70 | } 71 | 72 | walker.reset(); 73 | } 74 | 75 | /** End the evaluation of the current generation */ 76 | function endEvaluation(){ 77 | console.log('Generation:', neat.generation, '- average score:', Math.round(neat.getAverage())); 78 | console.log('Fittest score:', Math.round(neat.getFittest().score)); 79 | 80 | // Networks shouldn't get too big 81 | for(var genome in neat.population){ 82 | genome = neat.population[genome]; 83 | genome.score -= genome.nodes.length * SCORE_RADIUS / 10; 84 | } 85 | 86 | // Sort the population by score 87 | neat.sort(); 88 | 89 | // Init new pop 90 | var newPopulation = []; 91 | 92 | // Elitism 93 | for(var i = 0; i < neat.elitism; i++){ 94 | newPopulation.push(neat.population[i]); 95 | } 96 | 97 | // Breed the next individuals 98 | for(var i = 0; i < neat.popsize - neat.elitism; i++){ 99 | newPopulation.push(neat.getOffspring()); 100 | } 101 | 102 | // Replace the old population with the new population 103 | neat.population = newPopulation; 104 | neat.mutate(); 105 | 106 | neat.generation++; 107 | startEvaluation(); 108 | } 109 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/target-seekingai/player.js: -------------------------------------------------------------------------------- 1 | function Player(genome){ 2 | this.x = START_X; 3 | this.y = START_Y; 4 | this.vx = 0; 5 | this.vy = 0; 6 | this.r = 6; 7 | 8 | this.brain = genome; 9 | this.brain.score = 0; 10 | 11 | players.push(this); 12 | } 13 | 14 | Player.prototype = { 15 | /** Update the stats */ 16 | update: function(){ 17 | var input = this.detect(); 18 | var output = this.brain.activate(input); 19 | 20 | var moveangle = output[0] * 2 * PI; 21 | 22 | // Calculate next position 23 | this.ax = Math.cos(moveangle); 24 | this.ay = Math.sin(moveangle); 25 | this.vx += this.ax; 26 | this.vy += this.ay; 27 | 28 | // Limit speeds to maximum speed 29 | this.vx = this.vx > MAX_SPEED ? MAX_SPEED : this.vx < -MAX_SPEED ? -MAX_SPEED : this.vx; 30 | this.vy = this.vy > MAX_SPEED ? MAX_SPEED : this.vy < -MAX_SPEED ? -MAX_SPEED : this.vy; 31 | 32 | this.x += this.vx; 33 | this.y += this.vy; 34 | 35 | // Limit position to width and height 36 | this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x; 37 | this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y; 38 | 39 | if(this.x == 0 || this.x == WIDTH) this.vx = -this.vx; 40 | if(this.y == 0 || this.y == HEIGHT) this.vy = -this.vy; 41 | 42 | this.score(); 43 | }, 44 | 45 | /** Calculate fitness of this players genome **/ 46 | score: function(){ 47 | var dist = distance(this.x, this.y, walker.x, walker.y); 48 | if(!isNaN(dist) && dist < SCORE_RADIUS){ 49 | this.brain.score += SCORE_RADIUS - dist; 50 | } 51 | 52 | // Replace highest score to visualise 53 | highestScore = this.brain.score > highestScore ? this.brain.score : highestScore; 54 | }, 55 | 56 | /** Display the player on the field, parts borrowed from the CodingTrain */ 57 | show: function(){ 58 | // Draw a triangle rotated in the direction of velocity 59 | var angle = angleToPoint(this.x, this.y, this.x + this.vx, this.y + this.vy) + HALF_PI; 60 | var color = activationColor(this.brain.score, highestScore); 61 | 62 | push(); 63 | translate(this.x, this.y); 64 | rotate(angle); 65 | 66 | fill(color); 67 | beginShape(); 68 | vertex(0, -this.r * 2); 69 | vertex(-this.r, this.r * 2); 70 | vertex(this.r, this.r * 2); 71 | endShape(CLOSE); 72 | 73 | pop(); 74 | }, 75 | 76 | /** Detect and normalize inputs */ 77 | detect: function(){ 78 | var dist = Math.sqrt(this.x, this.y, walker.x, walker.y) / Math.sqrt(WIDTH**2 + HEIGHT**2); 79 | var targetAngle = angleToPoint(this.x, this.y, walker.x, walker.y) / TWO_PI; 80 | var vx = (this.vx + MAX_SPEED) / MAX_SPEED; 81 | var vy = (this.vy + MAX_SPEED) / MAX_SPEED; 82 | var tvx = (walker.vx + MAX_SPEED) / MAX_SPEED; 83 | var tvy = (walker.vy + MAX_SPEED) / MAX_SPEED; 84 | 85 | // NaN checking 86 | targetAngle = isNaN(targetAngle) ? 0 : targetAngle; 87 | dist = isNaN(dist) ? 0 : dist; 88 | 89 | return [vx, vy, tvx, tvy, targetAngle, dist]; 90 | }, 91 | }; 92 | -------------------------------------------------------------------------------- /mkdocs/theme/js/articles/target-seekingai/walker.js: -------------------------------------------------------------------------------- 1 | function Walker(){ 2 | this.x = START_X; 3 | this.y = START_Y; 4 | this.vx = 0; 5 | this.vy = 0; 6 | 7 | this.r = 10; 8 | 9 | this.angle = Math.random() * Math.PI * 2; 10 | } 11 | 12 | Walker.prototype = { 13 | /** Update the stats */ 14 | update: function(){ 15 | if(Math.random() > 0.5){ 16 | this.angle += Math.random()* 2 -1; 17 | } 18 | 19 | // Calculate next position 20 | this.ax = Math.cos(this.angle); 21 | this.ay = Math.sin(this.angle); 22 | this.vx += this.ax; 23 | this.vy += this.ay; 24 | 25 | // Limit speeds to maximum speed 26 | this.vx = this.vx > MAX_SPEED/2 ? MAX_SPEED/2 : this.vx < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vx; 27 | this.vy = this.vy > MAX_SPEED/2 ? MAX_SPEED/2 : this.vy < -MAX_SPEED/2 ? -MAX_SPEED/2 : this.vy; 28 | 29 | this.x += this.vx; 30 | this.y += this.vy; 31 | 32 | // Limit position to width and height 33 | this.x = this.x >= WIDTH ? WIDTH : this.x <= 0 ? 0 : this.x; 34 | this.y = this.y >= HEIGHT ? HEIGHT : this.y <= 0 ? 0 : this.y; 35 | 36 | if(this.x == 0 || this.x == WIDTH){ 37 | this.vx = -this.vx; 38 | this.angle += PI; 39 | } 40 | if(this.y == 0 || this.y == HEIGHT){ 41 | this.vy = -this.vy; 42 | this.angle += PI; 43 | } 44 | }, 45 | 46 | reset: function(){ 47 | this.x = START_X; 48 | this.y = START_Y; 49 | this.vx = 0; 50 | this.vy = 0; 51 | 52 | this.angle = Math.random() * Math.PI * 2; 53 | }, 54 | 55 | 56 | /** Display the walker on the field */ 57 | show: function(){ 58 | fill(0); 59 | ellipse(this.x, this.y, this.r*2); 60 | 61 | // Score radius 62 | noFill(); 63 | stroke('lightgreen'); 64 | strokeWeight(2); 65 | ellipse(this.x, this.y, SCORE_RADIUS*2); 66 | noStroke(); 67 | }, 68 | }; 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neataptic", 3 | "version": "1.4.7", 4 | "description": "Architecture-free neural network library with genetic algorithm implementations", 5 | "main": "./src/neataptic", 6 | "scripts": { 7 | "test:src": "mocha test/src.js test", 8 | "test:dist": "mocha test/dist.js test", 9 | "build:dist": "webpack", 10 | "build:docs": "cd mkdocs && mkdocs build --site-dir ../docs && cd ../", 11 | "build": "npm run build:dist && npm run build:docs", 12 | "deploy": "npm run build && npm run test:dist && npm publish", 13 | "test:travis": "npm run build:dist && npm run test:dist" 14 | }, 15 | "devDependencies": { 16 | "chai": "^4.1.2", 17 | "copy-webpack-plugin": "^4.0.1", 18 | "mocha": "^3.5.3", 19 | "semistandard": "*", 20 | "webpack": "^3.6.0" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/wagenaartje/neataptic.git" 25 | }, 26 | "keywords": [ 27 | "neural network", 28 | "machine learning", 29 | "genetic algorithm", 30 | "mutation", 31 | "neat" 32 | ], 33 | "author": { 34 | "name": "Thomas Wagenaar", 35 | "email": "wagenaartje@protonmail.com" 36 | }, 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/wagenaartje/neataptic/issues", 40 | "email": "wagenaartje@protonmail.com" 41 | }, 42 | "homepage": "http://wagenaartje.github.io/neataptic/", 43 | "engines": { 44 | "node": ">=7.6" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/architecture/connection.js: -------------------------------------------------------------------------------- 1 | /* Export */ 2 | module.exports = Connection; 3 | 4 | /******************************************************************************* 5 | CONNECTION 6 | *******************************************************************************/ 7 | 8 | function Connection (from, to, weight) { 9 | this.from = from; 10 | this.to = to; 11 | this.gain = 1; 12 | 13 | this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; 14 | 15 | this.gater = null; 16 | this.elegibility = 0; 17 | 18 | // For tracking momentum 19 | this.previousDeltaWeight = 0; 20 | 21 | // Batch training 22 | this.totalDeltaWeight = 0; 23 | 24 | this.xtrace = { 25 | nodes: [], 26 | values: [] 27 | }; 28 | } 29 | 30 | Connection.prototype = { 31 | /** 32 | * Converts the connection to a json object 33 | */ 34 | toJSON: function () { 35 | var json = { 36 | weight: this.weight 37 | }; 38 | 39 | return json; 40 | } 41 | }; 42 | 43 | /** 44 | * Returns an innovation ID 45 | * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) 46 | */ 47 | Connection.innovationID = function (a, b) { 48 | return 1 / 2 * (a + b) * (a + b + 1) + b; 49 | }; 50 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | CONFIG 3 | *******************************************************************************/ 4 | 5 | // Config 6 | var config = { 7 | warnings: false 8 | }; 9 | 10 | /* Export */ 11 | module.exports = config; 12 | -------------------------------------------------------------------------------- /src/methods/activation.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | ACTIVATION FUNCTIONS 3 | *******************************************************************************/ 4 | 5 | // https://en.wikipedia.org/wiki/Activation_function 6 | // https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons 7 | var activation = { 8 | LOGISTIC: function (x, derivate) { 9 | var fx = 1 / (1 + Math.exp(-x)); 10 | if (!derivate) return fx; 11 | return fx * (1 - fx); 12 | }, 13 | TANH: function (x, derivate) { 14 | if (derivate) return 1 - Math.pow(Math.tanh(x), 2); 15 | return Math.tanh(x); 16 | }, 17 | IDENTITY: function (x, derivate) { 18 | return derivate ? 1 : x; 19 | }, 20 | STEP: function (x, derivate) { 21 | return derivate ? 0 : x > 0 ? 1 : 0; 22 | }, 23 | RELU: function (x, derivate) { 24 | if (derivate) return x > 0 ? 1 : 0; 25 | return x > 0 ? x : 0; 26 | }, 27 | SOFTSIGN: function (x, derivate) { 28 | var d = 1 + Math.abs(x); 29 | if (derivate) return x / Math.pow(d, 2); 30 | return x / d; 31 | }, 32 | SINUSOID: function (x, derivate) { 33 | if (derivate) return Math.cos(x); 34 | return Math.sin(x); 35 | }, 36 | GAUSSIAN: function (x, derivate) { 37 | var d = Math.exp(-Math.pow(x, 2)); 38 | if (derivate) return -2 * x * d; 39 | return d; 40 | }, 41 | BENT_IDENTITY: function (x, derivate) { 42 | var d = Math.sqrt(Math.pow(x, 2) + 1); 43 | if (derivate) return x / (2 * d) + 1; 44 | return (d - 1) / 2 + x; 45 | }, 46 | BIPOLAR: function (x, derivate) { 47 | return derivate ? 0 : x > 0 ? 1 : -1; 48 | }, 49 | BIPOLAR_SIGMOID: function (x, derivate) { 50 | var d = 2 / (1 + Math.exp(-x)) - 1; 51 | if (derivate) return 1 / 2 * (1 + d) * (1 - d); 52 | return d; 53 | }, 54 | HARD_TANH: function (x, derivate) { 55 | if (derivate) return x > -1 && x < 1 ? 1 : 0; 56 | return Math.max(-1, Math.min(1, x)); 57 | }, 58 | ABSOLUTE: function (x, derivate) { 59 | if (derivate) return x < 0 ? -1 : 1; 60 | return Math.abs(x); 61 | }, 62 | INVERSE: function (x, derivate) { 63 | if (derivate) return -1; 64 | return 1 - x; 65 | }, 66 | // https://arxiv.org/pdf/1706.02515.pdf 67 | SELU: function (x, derivate) { 68 | var alpha = 1.6732632423543772848170429916717; 69 | var scale = 1.0507009873554804934193349852946; 70 | var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; 71 | if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } 72 | return fx * scale; 73 | } 74 | }; 75 | 76 | /* Export */ 77 | module.exports = activation; 78 | -------------------------------------------------------------------------------- /src/methods/connection.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | CONNECTION 3 | *******************************************************************************/ 4 | 5 | // Specifies in what manner two groups are connected 6 | var connection = { 7 | ALL_TO_ALL: { 8 | name: 'OUTPUT' 9 | }, 10 | ALL_TO_ELSE: { 11 | name: 'INPUT' 12 | }, 13 | ONE_TO_ONE: { 14 | name: 'SELF' 15 | } 16 | }; 17 | 18 | /* Export */ 19 | module.exports = connection; 20 | -------------------------------------------------------------------------------- /src/methods/cost.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | COST FUNCTIONS 3 | *******************************************************************************/ 4 | 5 | // https://en.wikipedia.org/wiki/Loss_function 6 | var cost = { 7 | // Cross entropy error 8 | CROSS_ENTROPY: function (target, output) { 9 | var error = 0; 10 | for (var i = 0; i < output.length; i++) { 11 | // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A 12 | error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); 13 | } 14 | return error / output.length; 15 | }, 16 | // Mean Squared Error 17 | MSE: function (target, output) { 18 | var error = 0; 19 | for (var i = 0; i < output.length; i++) { 20 | error += Math.pow(target[i] - output[i], 2); 21 | } 22 | 23 | return error / output.length; 24 | }, 25 | // Binary error 26 | BINARY: function (target, output) { 27 | var misses = 0; 28 | for (var i = 0; i < output.length; i++) { 29 | misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); 30 | } 31 | 32 | return misses; 33 | }, 34 | // Mean Absolute Error 35 | MAE: function (target, output) { 36 | var error = 0; 37 | for (var i = 0; i < output.length; i++) { 38 | error += Math.abs(target[i] - output[i]); 39 | } 40 | 41 | return error / output.length; 42 | }, 43 | // Mean Absolute Percentage Error 44 | MAPE: function (target, output) { 45 | var error = 0; 46 | for (var i = 0; i < output.length; i++) { 47 | error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); 48 | } 49 | 50 | return error / output.length; 51 | }, 52 | // Mean Squared Logarithmic Error 53 | MSLE: function (target, output) { 54 | var error = 0; 55 | for (var i = 0; i < output.length; i++) { 56 | error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); 57 | } 58 | 59 | return error; 60 | }, 61 | // Hinge loss, for classifiers 62 | HINGE: function (target, output) { 63 | var error = 0; 64 | for (var i = 0; i < output.length; i++) { 65 | error += Math.max(0, 1 - target[i] * output[i]); 66 | } 67 | 68 | return error; 69 | } 70 | }; 71 | 72 | /* Export */ 73 | module.exports = cost; 74 | -------------------------------------------------------------------------------- /src/methods/crossover.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | CROSSOVER 3 | *******************************************************************************/ 4 | 5 | // https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) 6 | var crossover = { 7 | SINGLE_POINT: { 8 | name: 'SINGLE_POINT', 9 | config: [0.4] 10 | }, 11 | TWO_POINT: { 12 | name: 'TWO_POINT', 13 | config: [0.4, 0.9] 14 | }, 15 | UNIFORM: { 16 | name: 'UNIFORM' 17 | }, 18 | AVERAGE: { 19 | name: 'AVERAGE' 20 | } 21 | }; 22 | 23 | /* Export */ 24 | module.exports = crossover; 25 | -------------------------------------------------------------------------------- /src/methods/gating.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | GATING 3 | *******************************************************************************/ 4 | 5 | // Specifies how to gate a connection between two groups of multiple neurons 6 | var gating = { 7 | OUTPUT: { 8 | name: 'OUTPUT' 9 | }, 10 | INPUT: { 11 | name: 'INPUT' 12 | }, 13 | SELF: { 14 | name: 'SELF' 15 | } 16 | }; 17 | 18 | /* Export */ 19 | module.exports = gating; 20 | -------------------------------------------------------------------------------- /src/methods/methods.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | METHODS 3 | *******************************************************************************/ 4 | 5 | var methods = { 6 | activation: require('./activation'), 7 | mutation: require('./mutation'), 8 | selection: require('./selection'), 9 | crossover: require('./crossover'), 10 | cost: require('./cost'), 11 | gating: require('./gating'), 12 | connection: require('./connection'), 13 | rate: require('./rate') 14 | }; 15 | 16 | /** Export */ 17 | module.exports = methods; 18 | -------------------------------------------------------------------------------- /src/methods/mutation.js: -------------------------------------------------------------------------------- 1 | /* Import */ 2 | var activation = require('./activation'); 3 | 4 | /******************************************************************************* 5 | MUTATION 6 | *******************************************************************************/ 7 | 8 | // https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) 9 | var mutation = { 10 | ADD_NODE: { 11 | name: 'ADD_NODE' 12 | }, 13 | SUB_NODE: { 14 | name: 'SUB_NODE', 15 | keep_gates: true 16 | }, 17 | ADD_CONN: { 18 | name: 'ADD_CONN' 19 | }, 20 | SUB_CONN: { 21 | name: 'REMOVE_CONN' 22 | }, 23 | MOD_WEIGHT: { 24 | name: 'MOD_WEIGHT', 25 | min: -1, 26 | max: 1 27 | }, 28 | MOD_BIAS: { 29 | name: 'MOD_BIAS', 30 | min: -1, 31 | max: 1 32 | }, 33 | MOD_ACTIVATION: { 34 | name: 'MOD_ACTIVATION', 35 | mutateOutput: true, 36 | allowed: [ 37 | activation.LOGISTIC, 38 | activation.TANH, 39 | activation.RELU, 40 | activation.IDENTITY, 41 | activation.STEP, 42 | activation.SOFTSIGN, 43 | activation.SINUSOID, 44 | activation.GAUSSIAN, 45 | activation.BENT_IDENTITY, 46 | activation.BIPOLAR, 47 | activation.BIPOLAR_SIGMOID, 48 | activation.HARD_TANH, 49 | activation.ABSOLUTE, 50 | activation.INVERSE, 51 | activation.SELU 52 | ] 53 | }, 54 | ADD_SELF_CONN: { 55 | name: 'ADD_SELF_CONN' 56 | }, 57 | SUB_SELF_CONN: { 58 | name: 'SUB_SELF_CONN' 59 | }, 60 | ADD_GATE: { 61 | name: 'ADD_GATE' 62 | }, 63 | SUB_GATE: { 64 | name: 'SUB_GATE' 65 | }, 66 | ADD_BACK_CONN: { 67 | name: 'ADD_BACK_CONN' 68 | }, 69 | SUB_BACK_CONN: { 70 | name: 'SUB_BACK_CONN' 71 | }, 72 | SWAP_NODES: { 73 | name: 'SWAP_NODES', 74 | mutateOutput: true 75 | } 76 | }; 77 | 78 | mutation.ALL = [ 79 | mutation.ADD_NODE, 80 | mutation.SUB_NODE, 81 | mutation.ADD_CONN, 82 | mutation.SUB_CONN, 83 | mutation.MOD_WEIGHT, 84 | mutation.MOD_BIAS, 85 | mutation.MOD_ACTIVATION, 86 | mutation.ADD_GATE, 87 | mutation.SUB_GATE, 88 | mutation.ADD_SELF_CONN, 89 | mutation.SUB_SELF_CONN, 90 | mutation.ADD_BACK_CONN, 91 | mutation.SUB_BACK_CONN, 92 | mutation.SWAP_NODES 93 | ]; 94 | 95 | mutation.FFW = [ 96 | mutation.ADD_NODE, 97 | mutation.SUB_NODE, 98 | mutation.ADD_CONN, 99 | mutation.SUB_CONN, 100 | mutation.MOD_WEIGHT, 101 | mutation.MOD_BIAS, 102 | mutation.MOD_ACTIVATION, 103 | mutation.SWAP_NODES 104 | ]; 105 | 106 | /* Export */ 107 | module.exports = mutation; 108 | -------------------------------------------------------------------------------- /src/methods/rate.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | RATE 3 | *******************************************************************************/ 4 | 5 | // https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 6 | var rate = { 7 | FIXED: function () { 8 | var func = function (baseRate, iteration) { return baseRate; }; 9 | return func; 10 | }, 11 | STEP: function (gamma, stepSize) { 12 | gamma = gamma || 0.9; 13 | stepSize = stepSize || 100; 14 | 15 | var func = function (baseRate, iteration) { 16 | return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); 17 | }; 18 | 19 | return func; 20 | }, 21 | EXP: function (gamma) { 22 | gamma = gamma || 0.999; 23 | 24 | var func = function (baseRate, iteration) { 25 | return baseRate * Math.pow(gamma, iteration); 26 | }; 27 | 28 | return func; 29 | }, 30 | INV: function (gamma, power) { 31 | gamma = gamma || 0.001; 32 | power = power || 2; 33 | 34 | var func = function (baseRate, iteration) { 35 | return baseRate * Math.pow(1 + gamma * iteration, -power); 36 | }; 37 | 38 | return func; 39 | } 40 | }; 41 | 42 | /* Export */ 43 | module.exports = rate; 44 | -------------------------------------------------------------------------------- /src/methods/selection.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | SELECTION 3 | *******************************************************************************/ 4 | 5 | // https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) 6 | 7 | var selection = { 8 | FITNESS_PROPORTIONATE: { 9 | name: 'FITNESS_PROPORTIONATE' 10 | }, 11 | POWER: { 12 | name: 'POWER', 13 | power: 4 14 | }, 15 | TOURNAMENT: { 16 | name: 'TOURNAMENT', 17 | size: 5, 18 | probability: 0.5 19 | } 20 | }; 21 | 22 | /* Export */ 23 | module.exports = selection; 24 | -------------------------------------------------------------------------------- /src/multithreading/multi.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | MULTITHREADING 3 | *******************************************************************************/ 4 | 5 | var multi = { 6 | /** Workers */ 7 | workers: require('./workers/workers'), 8 | 9 | /** Serializes a dataset */ 10 | serializeDataSet: function (dataSet) { 11 | var serialized = [dataSet[0].input.length, dataSet[0].output.length]; 12 | 13 | for (var i = 0; i < dataSet.length; i++) { 14 | var j; 15 | for (j = 0; j < serialized[0]; j++) { 16 | serialized.push(dataSet[i].input[j]); 17 | } 18 | for (j = 0; j < serialized[1]; j++) { 19 | serialized.push(dataSet[i].output[j]); 20 | } 21 | } 22 | 23 | return serialized; 24 | }, 25 | 26 | /** Activate a serialized network */ 27 | activateSerializedNetwork: function (input, A, S, data, F) { 28 | for (var i = 0; i < data[0]; i++) A[i] = input[i]; 29 | for (i = 2; i < data.length; i++) { 30 | let index = data[i++]; 31 | let bias = data[i++]; 32 | let squash = data[i++]; 33 | let selfweight = data[i++]; 34 | let selfgater = data[i++]; 35 | 36 | S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; 37 | 38 | while (data[i] !== -2) { 39 | S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); 40 | } 41 | A[index] = F[squash](S[index]); 42 | } 43 | 44 | var output = []; 45 | for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); 46 | return output; 47 | }, 48 | 49 | /** Deserializes a dataset to an array of arrays */ 50 | deserializeDataSet: function (serializedSet) { 51 | var set = []; 52 | 53 | var sampleSize = serializedSet[0] + serializedSet[1]; 54 | for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { 55 | let input = []; 56 | for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { 57 | input.push(serializedSet[j]); 58 | } 59 | let output = []; 60 | for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { 61 | output.push(serializedSet[j]); 62 | } 63 | set.push(input); 64 | set.push(output); 65 | } 66 | 67 | return set; 68 | }, 69 | 70 | /** A list of compiled activation functions in a certain order */ 71 | activations: [ 72 | function (x) { return 1 / (1 + Math.exp(-x)); }, 73 | function (x) { return Math.tanh(x); }, 74 | function (x) { return x; }, 75 | function (x) { return x > 0 ? 1 : 0; }, 76 | function (x) { return x > 0 ? x : 0; }, 77 | function (x) { return x / (1 + Math.abs(x)); }, 78 | function (x) { return Math.sin(x); }, 79 | function (x) { return Math.exp(-Math.pow(x, 2)); }, 80 | function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, 81 | function (x) { return x > 0 ? 1 : -1; }, 82 | function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, 83 | function (x) { return Math.max(-1, Math.min(1, x)); }, 84 | function (x) { return Math.abs(x); }, 85 | function (x) { return 1 - x; }, 86 | function (x) { 87 | var a = 1.6732632423543772848170429916717; 88 | return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; 89 | } 90 | ] 91 | }; 92 | 93 | multi.testSerializedSet = function (set, cost, A, S, data, F) { 94 | // Calculate how much samples are in the set 95 | var error = 0; 96 | for (var i = 0; i < set.length; i += 2) { 97 | let output = multi.activateSerializedNetwork(set[i], A, S, data, F); 98 | error += cost(set[i + 1], output); 99 | } 100 | 101 | return error / (set.length / 2); 102 | }; 103 | 104 | /* Export */ 105 | for (var i in multi) { 106 | module.exports[i] = multi[i]; 107 | } 108 | -------------------------------------------------------------------------------- /src/multithreading/workers/browser/testworker.js: -------------------------------------------------------------------------------- 1 | /* Export */ 2 | module.exports = TestWorker; 3 | 4 | /* Import */ 5 | var multi = require('../../multi'); 6 | 7 | /******************************************************************************* 8 | WEBWORKER 9 | *******************************************************************************/ 10 | 11 | function TestWorker (dataSet, cost) { 12 | var blob = new Blob([this._createBlobString(cost)]); 13 | this.url = window.URL.createObjectURL(blob); 14 | this.worker = new Worker(this.url); 15 | 16 | var data = { set: new Float64Array(dataSet).buffer }; 17 | this.worker.postMessage(data, [data.set]); 18 | } 19 | 20 | TestWorker.prototype = { 21 | evaluate: function (network) { 22 | return new Promise((resolve, reject) => { 23 | var serialized = network.serialize(); 24 | 25 | var data = { 26 | activations: new Float64Array(serialized[0]).buffer, 27 | states: new Float64Array(serialized[1]).buffer, 28 | conns: new Float64Array(serialized[2]).buffer 29 | }; 30 | 31 | this.worker.onmessage = function (e) { 32 | var error = new Float64Array(e.data.buffer)[0]; 33 | resolve(error); 34 | }; 35 | 36 | this.worker.postMessage(data, [data.activations, data.states, data.conns]); 37 | }); 38 | }, 39 | 40 | terminate: function () { 41 | this.worker.terminate(); 42 | window.URL.revokeObjectURL(this.url); 43 | }, 44 | 45 | _createBlobString: function (cost) { 46 | var source = ` 47 | var F = [${multi.activations.toString()}]; 48 | var cost = ${cost.toString()}; 49 | var multi = { 50 | deserializeDataSet: ${multi.deserializeDataSet.toString()}, 51 | testSerializedSet: ${multi.testSerializedSet.toString()}, 52 | activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} 53 | }; 54 | 55 | this.onmessage = function (e) { 56 | if(typeof e.data.set === 'undefined'){ 57 | var A = new Float64Array(e.data.activations); 58 | var S = new Float64Array(e.data.states); 59 | var data = new Float64Array(e.data.conns); 60 | 61 | var error = multi.testSerializedSet(set, cost, A, S, data, F); 62 | 63 | var answer = { buffer: new Float64Array([error ]).buffer }; 64 | postMessage(answer, [answer.buffer]); 65 | } else { 66 | set = multi.deserializeDataSet(new Float64Array(e.data.set)); 67 | } 68 | };`; 69 | 70 | return source; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/multithreading/workers/node/testworker.js: -------------------------------------------------------------------------------- 1 | /* Export */ 2 | module.exports = TestWorker; 3 | 4 | /* Import */ 5 | var cp = require('child_process'); 6 | var path = require('path'); 7 | 8 | /******************************************************************************* 9 | WEBWORKER 10 | *******************************************************************************/ 11 | 12 | function TestWorker (dataSet, cost) { 13 | this.worker = cp.fork(path.join(__dirname, '/worker')); 14 | 15 | this.worker.send({ set: dataSet, cost: cost.name }); 16 | } 17 | 18 | TestWorker.prototype = { 19 | evaluate: function (network) { 20 | return new Promise((resolve, reject) => { 21 | var serialized = network.serialize(); 22 | 23 | var data = { 24 | activations: serialized[0], 25 | states: serialized[1], 26 | conns: serialized[2] 27 | }; 28 | 29 | var _that = this.worker; 30 | this.worker.on('message', function callback (e) { 31 | _that.removeListener('message', callback); 32 | resolve(e); 33 | }); 34 | 35 | this.worker.send(data); 36 | }); 37 | }, 38 | 39 | terminate: function () { 40 | this.worker.kill(); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /src/multithreading/workers/node/worker.js: -------------------------------------------------------------------------------- 1 | var { multi, methods } = require('../../../neataptic'); 2 | 3 | var set = []; 4 | var cost; 5 | var F = multi.activations; 6 | 7 | process.on('message', function (e) { 8 | if (typeof e.set === 'undefined') { 9 | var A = e.activations; 10 | var S = e.states; 11 | var data = e.conns; 12 | 13 | var result = multi.testSerializedSet(set, cost, A, S, data, F); 14 | 15 | process.send(result); 16 | } else { 17 | cost = methods.cost[e.cost]; 18 | set = multi.deserializeDataSet(e.set); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/multithreading/workers/workers.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | WORKERS 3 | *******************************************************************************/ 4 | 5 | var workers = { 6 | node: { 7 | TestWorker: require('./node/testworker') 8 | }, 9 | browser: { 10 | TestWorker: require('./browser/testworker') 11 | } 12 | }; 13 | 14 | /** Export */ 15 | module.exports = workers; 16 | -------------------------------------------------------------------------------- /src/neataptic.js: -------------------------------------------------------------------------------- 1 | var Neataptic = { 2 | methods: require('./methods/methods'), 3 | Connection: require('./architecture/connection'), 4 | architect: require('./architecture/architect'), 5 | Network: require('./architecture/network'), 6 | config: require('./config'), 7 | Group: require('./architecture/group'), 8 | Layer: require('./architecture/layer'), 9 | Node: require('./architecture/node'), 10 | Neat: require('./neat'), 11 | multi: require('./multithreading/multi') 12 | }; 13 | 14 | // CommonJS & AMD 15 | if (typeof define !== 'undefined' && define.amd) { 16 | define([], function () { return Neataptic; }); 17 | } 18 | 19 | // Node.js 20 | if (typeof module !== 'undefined' && module.exports) { 21 | module.exports = Neataptic; 22 | } 23 | 24 | // Browser 25 | if (typeof window === 'object') { 26 | (function () { 27 | var old = window['neataptic']; 28 | Neataptic.ninja = function () { 29 | window['neataptic'] = old; 30 | return Neataptic; 31 | }; 32 | })(); 33 | 34 | window['neataptic'] = Neataptic; 35 | } 36 | -------------------------------------------------------------------------------- /test/dist.js: -------------------------------------------------------------------------------- 1 | if (typeof global.neataptic === 'undefined') { 2 | global.neataptic = require('../dist/neataptic'); 3 | } 4 | -------------------------------------------------------------------------------- /test/neat.js: -------------------------------------------------------------------------------- 1 | /* Import */ 2 | var chai = require('chai'); 3 | var assert = chai.assert; 4 | 5 | /* Shorten var names */ 6 | var { Network, methods, config } = neataptic; 7 | 8 | /* Turn off warnings */ 9 | config.warnings = false; 10 | 11 | /******************************************************************************************* 12 | Tests the effectiveness of evolution 13 | *******************************************************************************************/ 14 | 15 | describe('Neat', function () { 16 | it('AND', async function () { 17 | this.timeout(40000); 18 | 19 | // Train the AND gate 20 | var trainingSet = [ 21 | { input: [0, 0], output: [0] }, 22 | { input: [0, 1], output: [0] }, 23 | { input: [1, 0], output: [0] }, 24 | { input: [1, 1], output: [1] } 25 | ]; 26 | 27 | var network = new Network(2, 1); 28 | var results = await network.evolve(trainingSet, { 29 | mutation: methods.mutation.FFW, 30 | equal: true, 31 | elitism: 10, 32 | mutationRate: 0.5, 33 | error: 0.03, 34 | threads: 1 35 | }); 36 | 37 | assert.isBelow(results.error, 0.03); 38 | }); 39 | it('XOR', async function () { 40 | this.timeout(40000); 41 | // Train the XOR gate 42 | var trainingSet = [ 43 | { input: [0, 0], output: [0] }, 44 | { input: [0, 1], output: [1] }, 45 | { input: [1, 0], output: [1] }, 46 | { input: [1, 1], output: [0] } 47 | ]; 48 | 49 | var network = new Network(2, 1); 50 | var results = await network.evolve(trainingSet, { 51 | mutation: methods.mutation.FFW, 52 | equal: true, 53 | elitism: 10, 54 | mutationRate: 0.5, 55 | error: 0.03, 56 | threads: 1 57 | }); 58 | 59 | assert.isBelow(results.error, 0.03); 60 | }); 61 | it('XNOR', async function () { 62 | this.timeout(60000); 63 | 64 | // Train the XNOR gate 65 | var trainingSet = [ 66 | { input: [0, 0], output: [1] }, 67 | { input: [0, 1], output: [0] }, 68 | { input: [1, 0], output: [0] }, 69 | { input: [1, 1], output: [1] } 70 | ]; 71 | 72 | var network = new Network(2, 1); 73 | var results = await network.evolve(trainingSet, { 74 | mutation: methods.mutation.FFW, 75 | equal: true, 76 | elitism: 10, 77 | mutationRate: 0.5, 78 | error: 0.03, 79 | threads: 1 80 | }); 81 | 82 | assert.isBelow(results.error, 0.03); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /test/src.js: -------------------------------------------------------------------------------- 1 | if (typeof global.neataptic === 'undefined') { 2 | global.neataptic = require('../src/neataptic'); 3 | } 4 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* Import */ 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var webpack = require('webpack'); 5 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 6 | 7 | /* Update readme and read license */ 8 | var version = require('./package.json').version; 9 | var readme = fs.readFileSync('./README.md', 'utf-8').replace( 10 | /cdn\/(.*)\/neataptic.js/, `cdn/${version}/neataptic.js` 11 | ); 12 | fs.writeFileSync('./README.md', readme); 13 | 14 | var license = fs.readFileSync('./LICENSE', 'utf-8'); 15 | 16 | /* Export config */ 17 | module.exports = { 18 | context: __dirname, 19 | entry: { 20 | 'dist/neataptic': './src/neataptic.js', 21 | [`mkdocs/theme/cdn/${version}/neataptic`]: './src/neataptic.js' 22 | }, 23 | resolve: { 24 | modules: [ 25 | path.join(__dirname, 'node_modules') 26 | ] 27 | }, 28 | output: { 29 | path: __dirname, 30 | filename: '[name].js', 31 | library: 'neataptic', 32 | libraryTarget: 'umd' 33 | }, 34 | plugins: [ 35 | new webpack.NoEmitOnErrorsPlugin(), 36 | new webpack.BannerPlugin(license), 37 | new webpack.optimize.ModuleConcatenationPlugin(), 38 | new CopyWebpackPlugin([ 39 | { from: 'src/multithreading/workers/node/worker.js', to: 'dist' } 40 | ]) 41 | ], 42 | externals: [ 43 | 'child_process', 44 | 'os' 45 | ], 46 | node: { 47 | __dirname: false 48 | } 49 | }; 50 | --------------------------------------------------------------------------------