Skip to content

A c++ neural simulation based off of david miller's biosim4

License

Notifications You must be signed in to change notification settings

oxi-dev0/NeuralSim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NEURALSIM

Repo Size Stars Forks Watchers

A C++ neural evolution simulator

This program simulates neural evolution over generations through the goal of survival.

Please Note: This was inspired by David R. Miller's simulator, and is just a quick project i wanted to write; It does not have very optimised / clean code.

Important

When you clone this repository, you must use the argument "--recursive" to make sure it pulls all the submodules.

Branches

  • main - This is the normal branch, just the base program.
  • gpu-acceleration-wip - This is where i am working on GPU Acceleration using compute shaders. I do not know if this will work well to speed up simulation.

Features

  • Generational Simulator
  • Neural Map Viewer / Visualiser
  • Shape Parsing Language
  • GPU Acceleration
  • Simulation of custom Neural Maps

Dependencies

Note: These are all included in the repo, and all (apart from FFMPEG) are statically linked into the program
  • Premake - VS Project Generation
  • SFML - Window/Image Rendering
  • FFMPEG - Video Rendering
  • mINI - INI Config Reading
  • nodesoup - Fruchterman-Reingold graph positioning
  • spdlog - Output logging

Program Usage

A compiled version of the program can be found in bin/Release-windows-x86_64/

Simulation

  1. Edit config/config.ini in the program directory to change the simulation parameters
  2. Setup config/survival.shape in the program directory to configure the Survival Conditions
  3. Run NeuralSim.exe, optionally with the argument -c [.INI FILE]

Neural Map Visualisation

  1. Run NeuralSim.exe with the argument -v [.NM FILE]

Command Line Arguments

Argument Description
-h Outputs program usage
-s Simulate mode [DEFAULT]
-v [*.nm] Visualise mode
-c [*.ini] Specify configuration file [DEFAULT: config/config.ini]
-sc [*.shape] Specify the survival shape file [DEFAULT: config/survival.shape]
-k [int] Set the Fruchterman-Reingold constant [DEFAULT: 400]

Please Note: The square brackets in this documentation only show there is a token or parameter to change, the program will not understand your arguments if you include square brackets when executing the program. Also, the program does not support wildcards (*), this is only in the documentation to show that a specific file of that filetype is required.


Source

Note: You must have VS2022 installed to build from source

Project Setup

  1. Run GenerateScripts.bat to use premake to generate the Visual Studio 2022 project files
  2. Open NeuralSim.sln

Receptors

Receptors are defined in a Receptor enum in src/Classes/NeuralMap/Types.h
Receptor behaviour is defined in Cell::GetReceptorVal(NeuralNet::Receptor receptor) in src/Classes/NeuralMap/Receptors.cpp
Receptor name strings are defined in receptorName(Receptor receptor) in src/Classes/NeuralMap/DebugTypes.cpp

Effectors

Effectors are defined in an Effector enum in src/Classes/NeuralMap/Types.h
Effector behaviour is defined in ProcessEffectorQueue(int owner) in src/Classes/NeuralMap/Effectors.cpp
Effector name strings are defined in effectorName(Effector effector) in src/Classes/NeuralMap/DebugTypes.cpp

The Visualiser long name strings are defined in shrtNodeToLong(std::string shrt) in src/Visualise/Visualise.cpp

This section will be expanded along with comments in the source


Brief Documentation

This documentation will be expanded in the future, and I may make a youtube video explaining how the simulator and visualiser works (as in more technical / code orientated detail than David Miller's video)

Survival Conditions & Shape Files

The .shape file is a custom language that allows the program to parse shapes for the simulation. It is extremely basic right now, and is only used for survival conditions. In the future, they will be used to define walls inside the simulation. The language needs specific usage of spaces and newlines to parse correctly.

Shapes

Shape Arguments Example
CIRCLE [LOC X] [LOC Y] [RADIUS] CIRCLE 64 64 25
RECT [LEFT X] [RIGHT X] [TOP Y] [BOTTOM Y] RECT 64 128 0 128

Right now, shapes are used to define areas where cells will survive at the end of a generation. In the future, kill shapes will be added, where cells are killed off if they are inside the shape for a certain amount of time. Wall shapes will also be added so that dynamic maps for the cells to survive in can be created.

Conditions

Keyword Arguments Description Example
IF [LEFT VAL] [OPERATOR] [RIGHT VAL] Sets the current condition to parse with IF {GEN} > 200
ELSE Inverts the current condition ELSE
ENDIF Clears the current condition ENDIF

Please Note: Conditions do not support expression inputs yet. The left val and right val can only be a Token, or an integer. Expression parsing will come in the future. (This means that {STEPSPERGEN}/2 would be invalid)

Conditions allow shapes to change during a simulation. They are extremely simple right now and so do not support math operations as inputs. However, they do support all conditional operators (==, !=, >, >=, <, <=).

Tokens

Token Description
STEP The current simulation step
STEPSPERGEN The total amount of simulation steps in a generation
GEN The current generation

Please Note: Currently, Tokens can only be used in conditions.

Tokens are used for specifying simulation parameters in a shape file. They are used by enclosing the variable name in {...}; for instance: {GEN}, which returns the simulation's current generation.

Shape condition tokens are not very useful for survival configuration files as changing them during a generation wont do anything; It only matters what shape is active at the end of the generation, meaning only {GEN} is useful. I might add random tokens, and I definitely will add shape files for map configuration, so moving walls, etc, can be programmed.


An example of a .shape file is:

circle2rect.shape
~ Will switch to rectangle after generation 500
IF {GEN} >= 500
  RECT 64 128 0 128	~ Right side box
ELSE
  CIRCLE 64 64 25   	~ Center circle
ENDIF

~ Circle is always present in left corner (ENDIF clears the current condition)
CIRCLE 0 128 25

~ To use this run `NeuralSim.exe -sc config/circle2rect.shape`

~ can be used to comment either on a full line or after syntax


Definitions

Receptor Nodes

Receptors are inputs for neural maps that represent a cell's senses, and other inputs such as an oscillator as an internal clock. Right now there are 5 receptors (LOC_X, LOC_Y, RANDOM, AGE, and OSCILLATOR).

Effector Nodes

Effectors are outputs for neural maps that affect the cell's position. Right now there are 9 movement effectors, and 0 misc effectors. Misc effectors could be used to add pheremones or audio / visual communication between cells.

Internal Nodes

Internal nodes are intermediate nodes in neural maps that act as multipliers or variables for it. They allow inputs to be summed up and output into another node. They can also connect to themselves, which act as a sort of data delay, as a loop back connection uses the node's value from the last step.

Steps

Steps are an 'update' in the simulation. Each step a cell can move 1 position in any direction as a result of their neural map. Neural maps are simulated every step.

Generations

A Generation is a full lifetime of a cell. A generation has a certain number of steps and once a generation has passed, every cell that does not meet the survival conditions is killed off. Then, a new set of cells are spawned, with their Genome being a mutated mix of a random pair of cells that survived the previous generation.

Gene

A Gene is a connection between two Nodes in a Neural Map. A source is the node it comes from and a sink is the node it connects to. It has a weight and it multiplies it's source's output by its weight, then passes that to it's sink's input.

Genome

A Genome is a list of genes that defines a full neural map. Genomes can be mutilated and combined to form child genomes.

Neural Map

A Neural Map is a set of nodes that are connected using the connections described in a Genome. Each cell has a Neural Map, and for every step of the generation, every cell's neural map is simulated to determine the cell's behaviour that step.

Cell

A simple "microorganism" that contains a Neural Map, and a location on the grid.


Current State

The main simulator and visualiser is finished. What's mostly needed is optimisation, and a couple other features that make the program more fun to play around with.


Contribution

The most help is needed with optimisation, as I only have ~1 years experience with C++, and there will be many slow operations and calls that I wrote without realising how slow they are. I also dont have much time to work on the program, so any expansion with new receptors, effectors, etc is greatly appreciated :D


Screenshots / Videos

10,000 Gen Simulation with it's Neural Map Visualisation

generation10000.mov

About

A c++ neural simulation based off of david miller's biosim4

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages