This is the graduation design of my BSc degree in 2014. It's not polished well, actually my advisor was too busy to check the article and I did it just twice with my pitiful English and extremely poor academic writing ability. Also don't expect my coding skill. Take it easy ;)
[Abstract]: In This article firstly I tried to describe some general methods of designing artificial life model, then I implemented a basic model by programming in Python and Qt. The model contains basic objects as light energy, producer, consumer and decomposer, as well as several widgets. Besides, the model updates itself in real time.
[Keywords]: artificial life, computational biology, mathematical modeling
Artificial life is for researching, understanding and trying creating lives with computer. Lives are of enormous information, it's almost impossible to create a life in computer completely the same as real one, but rules and principles can be as brief as sentences, with limited rules we may still model life or generate life patterns in computer. Artificial life can also provide a tool to measure whether an experiment design and its model are strictly complete. If it can't be presented on computer, the model still lacks considering some essential factors.
World structure is actually the data structure. The usual structure is of matrix. Matrix can be with all kinds of inner structure. Like screen color matrix can be manifested as 2D matrix, and each pixel is of 3 values, on behalf of mix of the three basic colors: red, green and blue. The world itself doesn't have any special information, but can contain information. As for more possibility, it's better to design a world structure with more containers, but computer has its limit of computation and storage, we can't construct as many containers as we liked. Also in order to abstract the data into comprehensive and easily observing information, like changing objects on the screen, we may limit the size of the matrix according to the size of screen.
As mentioned above, the world can basically be a 2D matrix, then, to contain more kinds of information, every container can have one array or more, extremely the structure can be of matrix containing matrices. But this is not the end, every contained matrix can keep contains matrices iteratively, this is one way to generate incredible possibilities. Another way is to build a dynamic world. Exactly Iteration structure is as one kind of this, moreover, the same level of containers could move around and exchange, container could be generated or disappear in specific conditions. Designing Dynamic structure is a good way to save storage space of computer as well as generate more possibility, but it's hard to maintain.
If one basic matrix refers to one world, we also can construct several basic matrices as there are several worlds, and the worlds have some methods and conditions to share and exchange information with each other. While if we regard one basic 1D matrix as a mother world containing several child worlds, it will be the same. The difference of worlds is more about staticity or dynamicity, finity or infinity, and the structure of environment and life.
According to the design, the world is just data container, it doesn't contain any actual information by itself, even the basic concepts, space and time. Space and time are included in the environment factors. Compared to the real world, environment here refers to the non-life being, including physical objects(such as all kinds of rocks, crystals with different ratio of elements, light, sound, air), physics principles(such as four basic reactions, energy-mass equality). It's better to just construct the environment with essential and simple factors and then it can organize itself into complex physical beings, furthermore, we also wish that life pattern can be automatically generated from non-life being. It's one of the ultimate goals of artificial life and currently it's almost clueless to attempt. So for compromising we abstract some well-understanding, easily constructing and observing environment factors, and make them serve the evolution of the life system.
Space and time are special factors. Basically, when we constructed 2D world, with 2D matrix we can represent every space cell in the mutual matrix cell, and the 2D matrix can be constructed with equally long arrays. And when we need construct 3D dimension, we can just replace every matrix cell with an array to represent the additional dimension, so do we need to add more dimensions. Time is no need to construct, we represent it with the velocity of environment and life objects, and it's limited by computing speed of CPU and efficiency of program.
To build other environment factors into the world structure, we can add additional values, array or other data structure to each of the space cell, to these values, we can design different behaviors and relationships to them. Compared to life object, environment should at least provide basic energy source, such as light, heat, generate basic action, such as random movement. Its factors can't have any intentional or even active behavior, they are always passive and led by life objects.
It's too complicated to generally interpret what life is and how life works, at least, life is something that seems to oppose the physics fact – entropy increase. Presently, in sort of behaviors and relationships, life objects can be divided into three types: producer, who absorbs energy from environment, consumer, who eat producer and weaker species of same type, decomposer, who can decompose producer and consumer. The common characteristics of life contains: made of cells, reproduce, obtain and use energy, grow and develop/repair, respond to environment/stimuli. The design of life objects and its implementation with programming are according to these characteristics.
Real-time is very important to artificial life because the iteration times of data we need are always very large and even unpredictable. The first style somehow is also real-time as it didn't use recording, but every output matrix is kept in the window, which produces a huge burden to computer memory. While using Vispy need special knowledge and programming ability of OpenGL. The project is still making efforts to wrap OpenGL into high-level API.
So I turned to searching real-time plotting tool in Python and finally devoted my project to PyQtGraph, a project for visualization in Qt4 – which for creating User Interface in multi-platform. PyQtGraph has high performance in 2D plotting and also is easy to plot 3D object using OpenGL. Although there is not artificial life example in PyQtGraph, finally I successfully implemented my artificial life design with it.
At first I explored the official examples of PyQtGraph and found out a real-time video item program. I studied it and tried out my several small programs, like random movement tracker, randomly generating mergeable cells. Then I attempted to add several widgets like pause/resume button, but found that the Qt structure in the video item example was unable to add other widgets, other example from the official also couldn't suit my requirement. So I tried to find useful example directly from PyQt – API implementation of Qt with Python language. By tutorial and examples from http://zetcode.com/gui/pyqt4/ I successfully established my user interface for my project. Finally I kept on the design and implementation of my project and completed a basic raw world.
As showed above, the raw world contains a main graphic layout and three widgets – pause/resume button, time interval slider and four counters. In the graphic layout there are four kinds of object corresponding to the four counters. These four objects all move randomly in every time interval, when objects of same kind stayed in the same cell, they merged with brighter color, but their behaviors are somehow different. The grey ones are light bits. They are the major objects at the beginning. Imitating light in our real world, they can't merge with each other, when they stayed in the same cell, the color also got brighter, but in the next interval they would randomly divide. The green ones are producers. They can absorb light bit as energy and grow, give birth to baby in randomly adjacent cell when they mature and get extra energy, merge with each other when stay in the same cell and die when they exceed their brightness threshold. The red ones are consumers. They can eat producer. They merge, grow, mature, give birth and die the same as producer but can be set with different thresholds. The distinct difference is that when they saw decomposer two cells afront, which risked them to be killed by it, they would move toward the opposite of their direction. The blue ones are decomposer. They can decompose producer and consumer into light bits, in the meantime, they split into two in the opposite direction if they are big enough. They also split when they got too large. As currently designed, they never die or give birth, except being merged, their population is always the same.
As the code showed from appendix, from line 115 to 126, there are several attributes, smallest objects are displayed as BIT on RGBa color system, their RGB values are fix and the alpha value will decide individual difference of same kind. The raw world is wrapped in the class EnvAndLife from line 130 to 453. At first, from line 131 to 170, I used pseudorandom number generating function generate random distribution for each kind of object. With r – a zero to one random number matrix – at line 133, 138, 143, 148, etc, the initial population can be set as we want. At line 178, 300, etc, a temporary matrix is set to store objects after their movements so that every individual won't interfere each other in the procedure of update of movement. Although iteration is used to change movement, with the temporary matrix every object will still move at the same time in every time interval. At line 188, 191, etc, "%" is a modulus, with it object can move from edge of the world to the opposite edge. As showed at line 195, 317, etc, after update of behaviors, the temporary matrix is copied into the origin data.
At line 186, 219, etc, a four integer random sequence is generated, it's using for random movement. There is one interesting phenomenon by four direction movement, that every adjacent object never interferes with each other or stays in the same cell if we don't set extra behavior, because in every update, they can exchange place but cannot move to the same place. If so, there will be actually two worlds. From line 261 to 290 it's the birth giving function, with it, producer or consumer can give birth a baby in the adjacent cell, as a result, an object especially a light bit can move into another phase by transforming into a producer or consumer first.
Producers or consumers can die and transform into light bit if their alpha value is too big, as showed from line 310 to 314, 328 to 332, or if they encounter decomposer. Light bit, producer and consumer, their minimal alpha value are all 20 (line 119 to 121), but decomposer are 60 (line 122), it's because decomposer never transform into other kinds of object, Setting value of 60 helps them clearly display in the screen. To the world, the total alpha value of all the objects never changes, this is to imitate Energy Equivalence.
When testing program as table 1 shown below, the threshold of r value for envdata is 0.7 (line 138), which mean in world of size 100_100, the possible maximum amount of all objects is approximately: (1 - 0.7)_0.5_100_100 = 1500
|Size of the World||Update Times||Special Condition||1/sec||2/sec||3/sec||4/sec||5/sec||Average/sec|
|100*100||100||Cancel Environment Energy Update||2.399||2.445||2.475||2.354||2.429||2.420|
|100*100||100||Cancel All Three Life Objects Update||3.596||3.505||3.529||3.500||3.495||3.525|
|100*100||100||Cancel Counting Widget||3.254||3.186||3.287||3.291||3.186||3.241|
As shown above, In a world of 100_100 cells, with smallest time interval setting(1millisecond), currently running time of the program is approximately 4.260 seconds in the first 100 updates. Since the world keeps changing after update, in the first 1000 updates, running time will become around 38.67 seconds. It's because the amount of light bits is decreasing quickly at the beginning. If extending the world to 100_200 cells, it takes about 8.485 seconds, which is almost double of the first one. Also in the world of 200_200 cells, it takes about 18.71 seconds, it's about double of world of 100_200 cells. It seems spending time is linear to the size of the world. But when the world is of 200*300 cells, the running time will increase to about 43.57 seconds. It seems time cost is exploding. I found out it's somehow because of pixel rendering, I zoomed out the pixels to keep more cells in the windows of same size and it went like this, while when I just expanded the windows instead of changing the size of pixels, the running time decreased to about 31 seconds, nevertheless, to the size of the world, the time cost was not linear.
The cost of time most comes from the update of light bits. If we cancel the it, time cost will decrease from 4.260 to 2.420, while if we cancel the update of all three life objects, time cost just decreases to 3.525. It seems that using dictionary to store life objects is a good choice, which avoids many void calculations of matrix. Hence the world can add many more life objects and still has good performance.
Currently this version can just generate a stable world. In testing, I didn't find any outstanding pattern. As life objects are modeled to imitate producer, consumer and decomposer, the world can be used to do ecology experiments. Actually there are many variables in this raw world, changing them and observing the world may attain some valuable principles.
In one developing version, there is a special pattern as shown below:
In this version there is still no decomposers. According to the design, the life objects in mature pass all energy(alpha value) to baby it absorbs or eats. Consequently, the objects never die if they don't merge with others or be killed by others. With a lot of energy or foods around, the objects keep multiplying and generating such a pattern. Because the default maximum of alphavalue is 255. As tested, if there are too many alpha values of objects exceeding 1000, the display of the world will crash. It's the ending of this version.
As objects almost keep random movements in the raw world, it's still very amazing to generate such a pattern. In artificial life, it can be called as an attractor. If the world was sound, further observation and research can be taken. What are the conditions to generate such a pattern? How large the pattern can be with limited energy in the world? What is happening at the edge of it?
First, as describing above, now lifespan is determined by alpha value, which restrains the world to be more flexible and sounder. So I plan to add additional container to store age. With it the lifespan will determine by the update times of the world so that lifespan will also approach more to it in our reality.
Secondly, I plan to add some combining rules to the world. For example, as consumers eat producers but avoid decomposers in their movements, if producers combine with decomposers and move together with them, they will have higher probability to survive. With combining rules, the world may be also easier to generate patterns.
Thirdly, I plan to extend the world into 3D dimension. As shown above, in the developing version the objects will converge in an area, we can consider it that the environment is under high pressure. There are two methods to release it, one is that the environment digests it by itself. The other is that some of the objects jump into other dimension. This is also one way to extend 2D world into 3D. Exactly I wish that some rules which are only set in the 2D dimension can automatically extend to other dimensions.
Copied from http://hwp.ocps.net/tl/knoxs/Links/5MainCharacteristicsofLife.htm
In the official package, it came from examples/graphics item/ImageItem/video.
Source code: https://github.com/stbinan/raw-world