Alrium/README.md

275 lines
11 KiB
Markdown

# newAIrium description paper
AIrium is an effort to create a working, complex artificial life simulation environment.
### Description
This new iteration of the project focuses on solving the problems of the first:
- variety in creature body and mind structure
- removing evolution limits (such as brain size)
- allowing different species to mate and produce possibly stable children
- speed: trying to get the simulation to be as fast as possible on consumer grade hardware
- documentation: having an actual model to follow
- concurrency: try to enable the maximum concurrency when simulating the world, to the point that multiple
networked computers may collaborate and work together to simulate a world faster or help each other into
achieving meaningful results faster.
- java being used to write the implementation
#### Possible Applications
- studying evolution dynamics
- discovering new approaches at common problems by looking at how the simulated machines solved them
- learning how to create the environment necessary for a specific kind of evolution to take place
- having fun designing such a world and implementing a simulator for it
- having fun manually designing and creating structures
- having fun looking at machines interacting with the world and each other
- bragging about having designed and implemented such a simulation
- figuring out wether it would actually work
- distributing a creative alternative to a fish tank
### World
The world is a matrix where each cell is either empty or occupied by a structure.
Every structure occupies only one cell.
### Structures and Creatures
- a structure is a matrix where each cell is either empty or occupied by a Block.
- each adiacent Block can be connected.
- the blocks make up both the body and, if the blocks are connected, the mind.
- structures can move in the world, but can't occupy the same space of another structure.
A structure with an operational mind governing the body is called a creature or machine.
There are four kinds of blocks:
- __neuron blocks__ make the calculations
- __action blocks__ let a structure do something
- __sensor blocks__ let a structure know something about itself or anything else
- __resource blocks__ can be interacted with, causing some effects
### Signals
- a signal is a floating point value. Each block stores a signal.
- a signal is always between -1 and 1 included.
### Connection
- Each block can be connected to every other adiacent block (diagonals too),
so each block has 9 input connection weights: one for each neighbor and one for itself.
- A connection _is_ a weight, which is a floating point number. All connections are _inputs_.
- A neuron block's output is its adiacent blocks's current stored signals multiplied by the appropriate weight.
- the weight (or connection) is a floating point number between -1 and 1 included.
- If the connection is `0`, then there's no connection
- if the connection is `not 0` then there is a connection
- if the connection is `1` then there is a full positive connection, meaning the source value passes
intact to the destination
- if the connection is `-1` then the exact opposite of the input value passes to the destination
- the highest `abs(val) where val is the connection/weight` is, the stronger the connection
A signal can be any floating point value between -1 and 1.
- any signal higher than 1 will be considered to be 1
- any signal lower than -1 will be considered to be -1
### Neuron (Processing) Blocks
- new neuron blocks contain the `0` signal (null signal).
- neuron blocks store a signal until it is changed. The signal is calculated again at every iteration of the
simulation
- a neuron block's signal is the sum of all the incoming values, divided then by the sum of all the weights.
- an incoming value is the signal coming from a connection multiplied by the connection weight.
### Action (Output) blocks
They take an input signal and act by doing something, for example:
- they move the body in space
- they eject something
- they change color
- they interact with other structures
- they "eat" a block
- nothing (can be useful to stop signals from passing through)
### Sensor (Input) blocks
They give adiacent blocks a signal.
Some examples:
- they communicate how far is the first structure in a straight line
- they communicate the amount of structures in relation to blank spaces in an area (popularity in an area)
- they communicate the color/type/activity of the first block in a straight line
- they communicate information about the presence of a particular kind of structure in a direction
- they communicate information about the structure itself, like integrity of adiacent blocks
Generated signals are floating point numbers ranging from -1 to 1 included.
### Combined (Input+Output) blocks
They act as Sensor blocks and Action blocks at the same time.
Examples:
- a "mouth" block that can communicate wether food is available to eat and can receive eat
commands at the same time
### Reproduction and evolution
This requires two action blocks:
- the egg block
- the fertilizer block
machines can of course have both blocks, or even multiples of them.
- the egg block leaves a structure behind, an egg. This egg will either be fertilized or deplete energy and die.
- the fertilizer block can be used on egg structure to fertilize them
#### Hatching
When the egg hatches, a structure is born. The structure is built using a combination of the father's and the mother's blocks, then a mutation is applied to the result.
## Energy
This requires some new blocks:
- the battery block (first mentioned resource block)
- the energy drain block
- the generator block
- the stomach block
- the energy drain block sucks energy from a structure's batteries.
- the battery block stores energy and emits the current level to its connections
- the generator block uses up a lot of energy, then gives back slightly more
- the stomach block can be used to eat blocks from another structure. It then uses some energy to digest
the blocks, providing it back with an extra amount after it's done.
#### Consumption
- each action block uses up a moderate amount of energy when activated
- each sensor block uses up a small amount of energy when activated
### Fitness of a structure
The fitness is calculated by dividing the creature's total harvested energy by the creature's total consumed energy.
A creature with a fitness lower than or equal to 0 has all its batteries depleted. Then, it is
either revived by being charged somehow, or it can't do anything and no mind activity can take place.
This method to calculate fitness has many problems:
- What if a creature donates energy to others of the same species? It gets counted as energy consumption,
thus decreasing fitness
- What is a creature couldn't harvest energy because the circumstances weren't favorable?
The conclusion is that this system is far too complex to consider fitness evaluation.
### Complexity of a structure
The complexity of a structure is:
- if the fitness is `> 0`: the sum of the complexity of all its blocks.
- if the fitness is `<= 0`: 0
Complexity of a block starts at 0, then:
- increases by 1 for every not null connection of the block, if the block is an input block
- increases by x for every output block, depending on the specific block
The point of structure complexity is to try and approximately figure out how computationally expensive it is
to compute an itearation of the simulation for the structure
## Primordial world
The world should be composed of a variety of huge, small and anything in between energy farming or storage
structures.
Even better, there should be structures generating energy and shipping it off in space.
### Primordial creature
Since we can't expect that interesting machines pop up from nothing in our simulation, we need to design one.
On Earth, it took billions of years for something to show up, but we want to speed things up a little bit.
This machine needs:
- to search for energy sources
- to find energy sources and get there
- to use energy sources to fill up batteries
- to successfully create fertilized eggs
From there, maybe something smarter can show up. It is __essential__ that the user can save a machine at any time,
even early in an implementation. We __don't__ want to lose good machines!
## Interface
It is very important to give the user the ability to see the world in motion.
The interface should be structured akin to the following guidelines:
- a world navigation screen
- lets the user create an empty structure (needs at least 1 block)
- structure navigation screen
- ability to save the structure to file
- has a small _selected block_ sidebar with block informaton
- lets the user clear cells or set a block to them
- block navigation screen
- provides all info about the block and signal activity information
- lets the user view all connections and edit them
- lets the user edit the block type, preserving the connections
A sidebar has controls to handle simulation speed and pausing and other information such as:
- current CPU load.
- available energy in the world and amount being generated
- population information
## Implementation
The rust programming language is the best suited for a variety of reasons, namely:
- it is a fast language, well suited for performance intensive tasks
- it has a package manager that allows a programmer to focus on writing the code, not
desiging infrastructure, build systems, or coding functions already available in popular libraries
- it produces native, multiplatform binaries
- it obviously supports all the required features for the implementation of the simulation
But most importantly:
- it is built with a focus on type safety, concurrency and thread safety
- it's impossible to compile a thread unsafe concurrent program with the rust reference compiler
### Simulation iteration evaluation algorithm
- __MT__: main thread, controls the flow, HIGHEST PRIORITY
- __WT__: worker thread, evaluates a simulation iteration for one or more structures
- __AT__: applier threads, applies actions and writes the `new stored signal` into the `current stored signal`
for all blocks
One tick is evaluated using the following algorithm:
1. __MT__
- rebalances the __WTs__ work load, evaluating it based on structure complexity
- assignes newborn structures to the workers
- starts all the workers
1. __WTs__ work, __MT__ waits until they are done
1. __MT__ assigns actions returned by all the __WTs__ to a number of __ATs__
- tries to balance the __ATs__' work
- groups events from creatures that interact with each other together, keeping it thread safe but as distributed
across threads as possible
1. __ATs__ work, __MT__ waits untile they are done
It's probably not as fast as it gets, but it should be decent
#### Structure iteration evaluation algorithm
1. the `new stored signal` of each block is calculated
- if the block is a neuron block, calculate its `new stored signal` using immutable references to the other blocks
and the connection values.
- if the block is an input block, run its logic to figure out what its output should be
- if the block is an output block, add the action it should perform to the action queue
- This `new stored signal` is stored in a special variable without overwriting the `current stored signal`
so that the process can be easily accomplished in multithreading execution environments.
__Note:__ the bigger a machine, the slower it reacts to inputs because signals need more time to travel through the body