In genetic programming, at least how I am doing it there is some sort of instruction set. In this case, I have about 30 assembly like operations including the basic save, load, swap, simple math and such. Those plus some registers and a few more advanced math operations (floating point operations, sin, cos, exp, log) make up a small but hopefully Turing complete language. Then data is randomly generated to form the opcodes and oprands for an entity. That entity is run with those instructions in a simulator. In this case, the simulator allows the program to operation on a memory block of 64k 32-bit integers. The simulator lets it run for a bunch of operations and then halts it. The simulator can't just let it run till it calls terminate because it may never call terminate and might loop forever. After that is done, the simulator takes that memory space and treats it as if it were a bitmap. The bitmap is scanned to see how good it is. Points are given for unique colors and for pixels being populated.
Entities that are found fit are 'mated' with other entities. This means instructions are copied from both parents to form a new entity.
This goes on for a number of generations and eventually you get something that at least manages to draw some pixels. If I let it run forever, it would eventually maximize the points it can be given by whatever method I am using to determine fitness. In this case, I don't want that. So the images have to be judged by something more advanced. In this case people will judge them. The generations will be slower, but the results might be interesting.
I am not releasing code yet because it is embarrassing. I will release it after I clean it up a bit. It is currently pretty ugly and hacked together. I might eventually build it into a relatively generic genetic programming library so it can easily be applied to a variety of tasks.
Update: I've changed things around to handle much larger images (4600x7000) suitable for backgrounds and posters. So rather than a 64k block, it is 33.6M 32-bit integers. I have most of the computers in my house working on processing for it.
This isn't up to any reasonable coding standards. It is just something I hacked together. Please don't hate me.
The key bits are in Entity and the Op* files. Simulate also has some magic in pool manipulation. It also has lots of DB management kelp.
The following are all the instructions that the programs can do. They manage to write out the image data with only these operations.
There are five 32-bit registers, R1 through R5. R1 is used as a general register. R2 is almost always used as an indirection register. This means most instructions that use R2 actually operate on the value at the memory address indicated by R2. The rest are general purpose.
Things that use R2 as an address automatically wrap around. So if the memory size were 1000 and there was an access to index 1005, the access would actually go to index 6.
NULL - Do nothing JMP - Jump execution to code at address indicated by R2 JMPIF - Jump execution to code at address indicated by R2 iff R1 is zero LOADL1 - Load the literal value given by the oprand in R1 LOADL2 - Load the literal value given by the oprand in R1 STORE - Store the value currently in R1 to the memory address indicated by R2 LOAD - Load the value from the memory address indicated by R2 into R1 SWAPR2 - Swap the values of R1 and R2 SWAPR3 - Swap the values of R1 and R3 SWAPR4 - Swap the values of R1 and R4 SWAPR5 - Swap the values of R1 and R5 TERM - Terminate the program
IINC - Increment R1 by one INEG - Negate the value at R1 IADD - Add value of R1 to value stored at address indicated by R2, store result in R1 IDIV - Divide value of R1 to value stored at address indicated by R2, store result in R1 IMULT - Multiply value of R1 to value stored at address indicated by R2, store result in R1 ICOMP - Compare the value of R1 to zero. If R1 < 0 then R1=-1, if R1==0 then R1=0, if R1 > 0 then R1=1
FNEG - Negate the value at R1 FADD - Add value of R1 to value stored at address indicated by R2, store result in R1 FDIV - Divide value of R1 to value stored at address indicated by R2, store result in R1 FMULT - Multiply value of R1 to value stored at address indicated by R2, store result in R1 FCOMP - Compare the value of R1 to zero. If R1 < 0 then R1=-1, if R1==0 then R1=0, if R1 > 0 then R1=1 FSIN - Replace R1 with the sine of R1 FCOS - Replace R1 with the cosine of R1 FLOG - Replace R1 with the log of R1 FEXP - Replace R1 with the exp or R1
I2F - Consider R1 an integer - convert it to a float F2I - Consider R1 a float - convert to integer NPRIME - Read R1 as an integer N, replace R1 with the value of the N'th prime number
00000 LOADL2 0 00001 LOADL1 0x00ff00 # The value for blue 00002 STORE 00003 SWAPR2 00004 IINC 00005 SWAPR2 00006 LOADL1 00001 00006 JMP
Send Bitcoin tips to 12o9kVUrMLTivkk74HnNE76bTGmctit4ZV