Monday, 24 October 2011

Developer Journal 130

Converting genome data from version alpha to version bravo.

Grr. Genes have a value between 0 and 1. This value then gets interpreted into a range with a specified minimum and maximum. I was using the accessors in alpha to get the gene values and those accessors return the interpreted values and not the pre-interpreted values.

I'm suspecting more and more that a database would be useful to do serialization and to migrate the data from version to version.

I'm trying hard to not make GenomeBravo have to know about how GenomeAlpha works.

I'm suspecting more and more the code I'm writing to migrate the data from genome version alpha to genome version bravo will be soon obsolete and that I would have been better off using database techniques to store and transform the data but I don't have those database skills yet.

Friday, 21 October 2011

Developer Journal 129

Some rough notes, I'll write this up in a readable form soon.

---

I've been working on adding new capabilities to the robots. My goal is to convert the hard coded values to things I can change from text files and then have the robot sub-systems change dynamically.

If you increase the number of input / output groups, you have to change the indices. I'll also have to save the indices in order to do the updating.

Create a gene class.

When the brain updates, it pulls from the sensors.
When the robot updates, it pulls from the brain.

How to convert to a new structure?
Modify text file.
Modify genome.
Modify neural network

When a user creates a robot, they have to create the following files.
robotAlpha.cfg
+ bodyAlpha.cfg
+ brainAlpha.cfg
+ genomeAlpha.cfg
+ connectAlpha.cfg

You can change body, brain, genome, connect files by modifying robot. You can change which robot file to use through a setting the robot file.

1 shared CritParam, or 1 CritParam each

Focus on doing the minimum first

numInGroup 6

inGroup1 random
inGroup2 energy
inGroup3 red
inGroup4 green
inGroup5 blue
inGroup6 listen

inGroupRandom 1
inGroupEnergy 1
inGroupRed 3
inGroupGreen 3
inGroupBlue 3
inGroupListen 16

numOutGroup 8

outGroup1 eat
outGroup2 mate
outGroup3 fight
outGroup4 speed
outGroup5 yaw
outGroup6 light
outGroup7 focus
outGroup8 speak

outGroupEat 1
outGroupMate 1
outGroupFight 1
outGroupSpeed 1
outGroupYaw 1
outGroupLight 1
outGroupFocus 1
outGroupSpeak 16

Each genome in the text file should have a name, a variability flag, and a value

Each brain input / output has a name.
Each robot input / output has a name

// robot direction brain
visionOut > visionIn

// robot direction brain
forwardIn < forwardOut
leftIn < leftOut

I also want to be able to modify the neural network without modifying the genome.

When I serialize and after I load, I can check whether the settings file has changed.

The settings file can have a version number or I can check whether the parameters have changed. The problem with checking the parameters is that the process could take too long if each robot has their own genome param.

The reason I considered checking parameters is that I didn't want errors to come from manually incrementing the version numbers.

The genome checks the settings file.
The brain checks the genome.
The body checks the genome.

Thursday, 20 October 2011

Developer Journal 128

I'm excited. I finally get to work on a system to allow me to introduce different robot types. I'm determined to avoid hard coding and to preserve previous robot designs as I go.

I've also being thinking about the nature of work and what I would do if I didn't have to work.

I wish I knew a better way to do the genome crossover process. I'll have to look around for better ways of encoding data in genomes and doing the crossover and mutation processes.

The hard part is converting from one type of robot to another.

Wednesday, 19 October 2011

Developer Journal 127

Gender

Introducing gender to the population didn't quite produce the results I wanted. Introducing gender should have produced different results depending on how quickly I did it. Ideally introducing gender suddenly should have resulted in the population dying and introducing gender slowly should have resulted in the population surviving. That way, I could be sure that gender had a big enough impact to cause the population to have to change their behaviour.

Unfortunately, the population survived in both cases. Now I have to look for other indicators of behaviour change. I'll be going back to check whether the rate of same gender mating attempts changed over time. In addition, I'll have to introduce different colours to the genders to help the robots identify genders. I'll have to be careful choosing colours, pink for females seems obvious but wrong.

Pheromones

This brings up new problems, what happens if robots aren't facing each other? The suggestion I was given was to imagine the robots identified gender based on scent. So when robots are near each other they can tell whether another robot is male or female if they are close enough to each other. This kind of goes against a few ideas I've had. Firstly, you shouldn't have to interpret things for the robots and this feels like some kind of interpretation is going on. Secondly, I can't fit this neatly into my idea of basing on how humans evolved. At the same time I'm going to give it a go, it won't take long to program (famous last words) and it'll provide more information about what's happening in the background.

Intention

The other thing I've been thinking about and it relates to the problem of robots facing each other is encouraging intentional behaviour. At the moment, if two robots are next to each other and happen to think about mating at the same time for a split second, they reproduce. It's like if you're sitting next to someone and if you both happen to think about sex you end up with a baby. My idea is that they have to do something that takes a prolonged effort. For example, they have to face each other for 5 seconds and in that time, both agree to reproduce. The same with food. That way, if they choose to reproduce they have to face another robot for a period of time and activate their pseudo mating mechanisms for a sufficient period of time and intensity.

Arms, Legs, and Maturation

At the same time I want to introduce the maturation condition, which makes younger robots depend on the help of older robots to survive. At the same, same time I want to introduce the arms and legs that I've been going on about for months now. Yeah, I should get to work, but writing this helps clarifies my thoughts.

The thing that would be useful to work on is the ability to introduce new neural network inputs and outputs on the fly. That's something that's useful for all three of my programming tasks. Once I have that feature, the task of implementing arms and legs becomes a lot smaller since I've done most of the physics programming.

This time, I've learned my lesson. Instead of modifying the neural network code, I'll make version two. It's weird, it's been so long since I've touched the neural network code that I don't know how the network gets set up. I suspect I'll find the physics code for arms and legs unfamiliar as well. Oh yeah, I want to do my game programming as well.

Sunday, 16 October 2011

Developer Journal 126

Grr. I realised while in the shower this morning that I had set up the simulation with a 100 by 100 world instead of a 200 by 200 world.

Then when I was at uni I realised I was setting up the gender condition incorrectly. Borrowing an idea from RPG games, same gender robots have to roll below a percentage in order to reproduce. For example if the limit is 50, robots have to roll in the range 1 to 100 and get below 50.

The problem was I was rolling in the range 1 to the limit. Yep. Moving on.

To be extra geeky, I'm changing it around. Robots have to roll above the threshold. For example if the percentage is 75, robots have to roll above 75 to succeed in reproducing if they are the same gender.


So much dumbness. First, the threshold was already at my limit because of serialization so even though I wanted it to start at 1 and then increase it wouldn't. Second, I was using the wrong timer to periodically increase the limit. If you program while you're tired or distracted, you're a bl#$$y idiot.

Friday, 14 October 2011

Developer Journal 125

Grr. My approximately 10 minute load time grew to way to long because of my memory tracking code. 
  • 3 hours, 33 minutes, 6 seconds, primary computer
  • 3 hours, 24 minutes, 55 seconds, secondary computer
 I'll have to disable the memory tracking code for normal use and only enable it for debugging purposes.

Some things I'm learning.
  • Don't code your own serialization system
  • Have a serialization strategy
  • Have a few global variables to makes things easier
  • Don't code your own memory tracking system
  • If you're starting to consider writing your own template code, you're probably on the wrong track

Thursday, 13 October 2011

Developer Journal 124

Yah! I finished the introducing the gender condition. It took me a lot longer than I expected. I have to get a whole bunch of assignment marking done. I've got a lot of experiments I can run while I mark. At the same time I'd like to get the maturation condition done as well.

I'd also like to figure out how to make the code easier to work with. Things are all over the place.

Grr. I had to do a bunch of extra work to get my memory tracking code to work with Boost Serialization. When Boost Serialization loads, I have to manually register the object because I don't know how to get Boost Serialization to use my New() function that wraps around the "new" operator.

Time to test whether my changes are compatible with my ongoing save files.

Running one experiment where I suddenly introduce gender to an ongoing population. On another computer I'm gradually introducing gender.

Sigh. I think my memory tracking code is making the load process take too long. Loading a file with 128 to 256 robots takes about 10 minutes normally.

Wednesday, 12 October 2011

Developer Journal 123

Grr. Lot's of assignment marking today. I'm going to finish the gender constraint so that I can run the simulations in the background.

I got the following error message that took me a while to fix.

-*- mode: compilation; default-directory: "~/polyworld/" -*-
Compilation started at Wed Oct 12 14:53:54

mingw32-make 
Scanning dependencies of target OgreApp
[  2%] Building CXX object CMakeFiles/OgreApp.dir/app/Serializer.cpp.obj
In file included from D:\agi\dep\boost_1_44_0/boost/serialization/static_warning.hpp:73:0,
                 from D:\agi\dep\boost_1_44_0/boost/serialization/export.hpp:38,
                 from D:\agi\polyworld\app\Serializer.cpp:10:
D:\agi\dep\boost_1_44_0/boost/mpl/print.hpp: In instantiation of 'boost::mpl::print< boost::serialization::boost_serialization_static_warning_line< 137> >':
D:\agi\dep\boost_1_44_0/boost/serialization/static_warning.hpp:92:13:   instantiated from 'boost::serialization::static_warning_test< false, 137="">'
D:\agi\dep\boost_1_44_0/boost/serialization/export.hpp:137:1:   instantiated from 'const boost::archive::detail::< unnamed>::guid_initializer< t>& boost::archive::detail::< unnamed>::guid_initializer< t>::export_guid() const [with T = World, boost::archive::detail::< unnamed>::guid_initializer< t> = boost::archive::detail::< unnamed>::guid_initializer< world>]'
D:\agi\polyworld\app\Serializer.cpp:60:1:   instantiated from here
D:\agi\dep\boost_1_44_0/boost/mpl/print.hpp:55:5: warning: comparison between signed and unsigned integer expressions

< /world>< /unnamed>< /t>< /unnamed>< /t>< /unnamed>< /t>< /unnamed>< /false,>< /boost::serialization::boost_serialization_static_warning_line< 137>< 

The clue was T = World. I forgot to make the destructor virtual. Oh Boost Serialization, oh how I love and hate thee.

Tuesday, 11 October 2011

Developer Journal 122

I've almost finished the code for making the world bigger over time. I can't believe it took so long. Hopefully introducing gender and pseudo ageing won't take so long.

Damn, damn, damn. I took almost 3 hours to solve a problem.

	

	// create a motion state
	obj->motionState.reset( new btDefaultMotionState( transform ) );

	// create a collision shape
	const btVector3 halfExtents( 0.5f, 0.5f, 0.5f );
	obj->collisionShape.reset( new btBoxShape( halfExtents ) );    

	// create a rigid body
	const float mass = obj->mass;
	btVector3 localInertia( 0.0f, 0.0f, 0.0f );
	// rigidbody is dynamic if is non zero    	
	if( mass != 0.0f ) {
	    obj->collisionShape->calculateLocalInertia( mass, localInertia );
	}
	btRigidBody::btRigidBodyConstructionInfo rbInfo( 
	    mass, obj->motionState.get(), obj->collisionShape.get(), localInertia );
	shared_ptr< agiRigidBody > rigidBody( new agiRigidBody( rbInfo ) );
	rigidBody->Init( obj );
	
	// add to dynamics world
	imp->dynamicsWorld->addRigidBody( rigidBody.get() );

	// set pointer in data object
	obj->rigidBody = rigidBody;

	// scale
	btVector3 bulletScale;
	bulletScale.setX( obj->scale.x() );
	bulletScale.setY( obj->scale.y() );
	bulletScale.setZ( obj->scale.z() );
	rigidBody->getCollisionShape()->setLocalScaling( bulletScale );

I didn't know I had to initialise localInertia. Most vectors I work with default to 0.0.

I was relying on similar code elsewhere and then when I changed over to this code I had to track that error down. Grr. For three hours I had things falling through my ground for no good reason. Yeah, I need to learn more about physics and the physics library I'm using.

Monday, 10 October 2011

Developer Journal 121

I'm currently writing some code to make the world bigger over time. In particular, I'm thinking about how to save the state of the world over time. I'm wary of using more of Boost Serialization. The world is pretty simple with four walls and a floor. I can serialize the world object or the wall and ground objects.

I remember reading that I should avoid file reading in constructors. I'll need to do some file reading to get parameters to control how the world changes over time. I need to do this in the constructor if I serialize the world object or else I will need to call an initialisation function after each time I load the world object.

I don't know whether to serialize the world object or just the ground and wall objects. When in doubt and analysis paralysis, my strategy is usually to do the obvious, easy, albeit dumb thing. Save the 4 walls, the ground, and the last update time. Do everything manually for now.

I'm finding I'm spending more time trying to do things the smart way than is worthwhile.

Even simpler, save the current world size and the last world update time.

Hmm, that means the currentWorldSize and the lastWorldUpdate is inside class SimData and outside class World. When I load class World, it should be good to go. Albeit, I have to manually do stuff for physics and graphics. I'll have to copy over currentWorldSize and lastWorldUpdate from class SimData to class World. Then I'll have variables doing the same thing in different places. Grr, I'll serialize the world.

Dang! I just realized my fancy memory registry class is limited by the serialization process. My idea was to wrap new in a function that creates a note in the memory registry. When an object goes out of scope it notifies the memory registry. When the memory registry goes out of scope it should have no notes. If it has notes then it means some objects were not released and there is a memory leak.

I originally stumbled because I couldn't figure out how to get it to work with classes that were not my own. Then I realized that I didn't need to. The point of the memory register was to make sure that I avoided cyclic dependencies in my code. All good, then I realized that I didn't know how to make Boost Serialization use my New() function. I have to register objects created by Boost Serialization with the memory register manually. Not ideal, but it'll work for now.