Index: /cpp/README.txt
===================================================================
--- /cpp/README.txt	(revision 118)
+++ /cpp/README.txt	(revision 119)
@@ -1,8 +1,8 @@
-_____ Building GDK test applications _____
+____________________ Building GDK test applications ____________________
 
 make -f frams/Makefile-GDK gdk_tests
 
 
-_____ Source directories _____
+___________________________ Source directories __________________________
 
   +- common          - general compatibility layer & utilities
@@ -11,7 +11,7 @@
       +- config      - GDK elements declarations
       +- errmgr      - error manager (logging/messaging)
-      +- genetic     - genetic module
-      |  +- oper     - genetic operators and GenoFX
-      |  +- conv     - genetic converters
+      +- genetics    - genetic operators and converters between formats
+      |  +- f1       - ...for genetic format f1
+      |  +- f9       - ...for genetic format f9
       +- model       - parts, joints, neurons
       +- neuro       - neural net simulation
Index: /cpp/frams/genetics/defgenoconv.cpp
===================================================================
--- /cpp/frams/genetics/defgenoconv.cpp	(revision 119)
+++ /cpp/frams/genetics/defgenoconv.cpp	(revision 119)
@@ -0,0 +1,70 @@
+#include "defgenoconv.h"
+
+#include GEN_CONFIG_FILE
+
+#ifdef USE_GENCONV_F10
+#include "conv/conv_f1.h"
+#endif
+#ifdef USE_GENCONV_F20
+#include "conv/conv_f2.h"
+#endif
+#ifdef USE_GENCONV_F32
+#include "conv/conv_f3.h"
+#endif
+#ifdef USE_GENCONV_F40
+#include "conv/conv_f4.h"
+#endif
+#ifdef USE_GENCONV_F41_TEST
+#include "conv/conv_f4.h"
+#endif
+#ifdef USE_GENCONV_F50
+#include "conv/conv_f5.h"
+#endif
+#ifdef USE_GENCONV_F60
+#include "conv/geno_f6.h"
+#endif
+#ifdef USE_GENCONV_F70
+#include "conv/conv_f7.h"
+#endif
+#ifdef USE_GENCONV_F81
+#include "conv/conv_f8tof1.h"
+#endif
+#ifdef USE_GENCONV_F90
+#include "conv/conv_f9.h"
+#endif
+
+DefaultGenoConvManager::DefaultGenoConvManager()
+{
+#ifdef USE_GENCONV_F10
+addConverter(new GenoConv_F1());
+#endif
+#ifdef USE_GENCONV_F20
+addConverter(new GenoConv_F20());
+#endif
+#ifdef USE_GENCONV_F32
+addConverter(new GenoConv_F32());
+#endif
+#ifdef USE_GENCONV_F40
+addConverter(new GenoConv_F40());
+#endif
+#ifdef USE_GENCONV_F41_TEST
+addConverter(new GenoConv_F41_TestOnly());
+#endif
+#ifdef USE_GENCONV_F50
+addConverter(new GenoConv_F50);
+#endif
+#ifdef USE_GENCONV_F60
+addConverter(new GenoConv_F60);
+#endif
+#ifdef USE_GENCONV_F70
+addConverter(new GenoConv_F70);
+#endif
+#ifdef USE_GENCONV_F81
+addConverter(new GenoConv_F8ToF1());
+#endif
+#ifdef USE_GENCONV_F90
+addConverter(new GenoConv_F90);
+#endif
+
+param.updatetab();
+}
Index: /cpp/frams/genetics/defgenoconv.h
===================================================================
--- /cpp/frams/genetics/defgenoconv.h	(revision 119)
+++ /cpp/frams/genetics/defgenoconv.h	(revision 119)
@@ -0,0 +1,19 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _DEFGENOCONV_H_
+#define _DEFGENOCONV_H_
+
+#include "genoconv.h"
+
+/// This GenoConvManager automatically registers the "standard" converters available in the GDK.
+/// All you have to do is create a single instance of this class somewhere in your application.
+/// @see genotest.cpp
+class DefaultGenoConvManager: public GenoConvManager
+{
+  public:
+DefaultGenoConvManager();
+};
+
+#endif
Index: /cpp/frams/genetics/f1/conv_f1.cpp
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.cpp	(revision 119)
+++ /cpp/frams/genetics/f1/conv_f1.cpp	(revision 119)
@@ -0,0 +1,489 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2013  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "conv_f1.h"
+#include <common/nonstd_stl.h>
+#include <common/framsg.h>
+#include <frams/util/multirange.h>
+#include <frams/util/multimap.h>
+#include <ctype.h>
+
+//#define v1f1COMPATIBLE
+
+F1Props stdprops={1, 0, 1, 0.4, 0.25, 0.25, 0.25, 0.25, 0.0, 1.0, 1.0, 1,
+		 0.2, 0.5,0.5,0.5 };
+
+class Builder
+{
+public:
+Builder(const char*g,int mapping=0):invalid(0),genbegin(g),usemapping(mapping),energ(0),energ_div(0),first_part_mapping(NULL) {}
+~Builder() {SAFEDELETE(first_part_mapping);}
+char tmp[222];
+bool invalid;
+Model model;
+const char *genbegin;
+SList neuro_f1_to_f0; // neuro_f1_to_f0(f1_refno) = actual neuro pointer
+Neuro *last_f1_neuro;
+SyntParam *neuro_cls_param;
+
+struct Connection { int n1,n2; double w;
+Connection(int _n1,int _n2, double _w):n1(_n1),n2(_n2),w(_w) {} };
+
+SListTempl<Connection> connections;
+int usemapping;
+MultiRange range;
+MultiRange *first_part_mapping;
+double lastjoint_muscle_power;
+double energ,energ_div;
+void grow(int part1,const char*g,Pt3D k,F1Props c);
+void setPartMapping(int p,const char* g);
+int growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g);
+int growPart(F1Props &c,const char *g);
+const char *skipNeuro(const char *z);
+const char* growNeuro(const char* t,F1Props &c,int&);
+void growConnection(const char* begin,const char* colon,const char* end,F1Props& props);
+int countBranches(const char*g,SList &out);
+SyntParam* lastNeuroClassParam();
+void addClassParam(const char* name,double value);
+void addClassParam(const char* name,const char* value);
+
+const MultiRange* makeRange(const char*g) {return makeRange(g,g);}
+const MultiRange* makeRange(const char*g,const char*g2);
+Part *getLastPart() {return getLastJoint()->part2;}
+Neuro *getLastNeuro() {return model.getNeuro(model.getNeuroCount()-1);}
+Joint *getLastJoint() {return model.getJoint(model.getJointCount()-1);}
+void addOrRememberInput(int n1,int n2,double w)
+		{
+		//if (!addInput(n1,n2,w,false))
+		connections+=Connection(n1,n2,w);
+		}
+bool addInput(int n1,int n2,double w,bool final)
+		{
+		if ((n1<0) || (n2<0) || (n1>=neuro_f1_to_f0.size()) || (n2>=neuro_f1_to_f0.size()))
+			{
+			if (final) FMprintf("GenoConvF1","addInput",FMLV_WARN,
+					    "illegal neuron connection %d <- %d (ignored)",n1,n2);
+			return 0;
+			}
+		Neuro *neuro=(Neuro*)neuro_f1_to_f0(n1);
+		Neuro *input=(Neuro*)neuro_f1_to_f0(n2);
+		neuro->addInput(input,w);
+		return 1;
+		}
+void addPendingInputs()
+		{
+		for(int i=0;i<connections.size();i++)
+			{
+			Connection *c=&connections(i);
+			addInput(c->n1,c->n2,c->w,true);
+			}
+		}
+};
+
+const MultiRange* Builder::makeRange(const char*g,const char*g2)
+{
+if (!usemapping) return 0;
+range.clear();
+range.add(g-genbegin,g2-genbegin);
+return &range;
+}
+
+void F1Props::wykluczanie()
+{
+double s=ruch+asym+odpor+wchl;
+ruch=ruch/s;
+asym=asym/s;
+odpor=odpor/s;
+wchl=wchl/s;
+}
+
+/** main conversion function - with conversion map support */
+SString GenoConv_F1::convert(SString &i,MultiMap *map)
+{
+const char* g=(const char*)i;
+Builder builder(g,map?1:0);
+builder.model.open();
+builder.grow(-1,g,Pt3D_0,stdprops); // uses Model::singleStepBuild to create model elements
+if (builder.invalid) return SString();
+builder.addPendingInputs();
+builder.model.startenergy=(builder.energ_div>0)?(builder.energ/builder.energ_div):1.0;
+builder.model.close(); // model is ready to use now
+if (map) builder.model.getCurrentToF0Map(*map); // generate f1-to-f0 conversion map
+return builder.model.getF0Geno().getGene();
+}
+
+void Builder::setPartMapping(int p,const char* g)
+{
+if (!usemapping) return;
+const MultiRange *r=makeRange(g);
+if (p<0)
+	{ //special case: mapping the part which is not yet created
+	if (first_part_mapping) first_part_mapping->add(*r);
+	else first_part_mapping=new MultiRange(*r);
+	}
+else
+	model.getPart(p)->addMapping(*r);
+}
+
+void Builder::grow(int part1,const char*g,Pt3D k,F1Props c)
+{
+int hasmuscles=0;
+k+=Pt3D(c.rot,0,c.skr);
+while(1)
+{
+switch(*g)
+	{
+	case 0: case ',': case ')': return;
+	case 'R': k.x+=0.7853; setPartMapping(part1,g); break;
+	case 'r': k.x-=0.7853;	setPartMapping(part1,g); break;
+	case 'Q': c.rot+=(1.58-c.rot)*0.3; setPartMapping(part1,g); break;
+	case 'q': c.rot+=(-1.58-c.rot)*0.3; setPartMapping(part1,g); break;
+#ifdef v1f1COMPATIBLE
+	case 'L': c.dlug+=(3.0-c.dlug)*0.3; setPartMapping(part1,g); break;
+#else
+	case 'L': c.dlug+=(2.0-c.dlug)*0.3; setPartMapping(part1,g); break;
+#endif                                       
+	case 'l': c.dlug+=(0.33-c.dlug)*0.3; setPartMapping(part1,g); break;
+	case 'A': c.asym+=(1-c.asym)*0.8;	c.wykluczanie(); setPartMapping(part1,g);  break;
+	case 'a': c.asym-=c.asym*0.4;	c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'I': c.wchl+=(1-c.wchl)*0.8;	c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'i': c.wchl-=c.wchl*0.4;	c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'S': c.odpor+=(1-c.odpor)*0.8; c.wykluczanie(); setPartMapping(part1,g); break;
+	case 's': c.odpor-=c.odpor*0.4; c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'M': c.ruch+=(1-c.ruch)*0.8;	c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'm': c.ruch-=c.ruch*0.4;	c.wykluczanie(); setPartMapping(part1,g); break;
+	case 'C': c.skr+=(2.0-c.skr)*0.25;	setPartMapping(part1,g); break;
+	case 'c': c.skr+=(-2.0-c.skr)*0.25; setPartMapping(part1,g); break;
+	case 'F': c.tarcie+=(4-c.tarcie)*0.2; setPartMapping(part1,g); break;
+	case 'f': c.tarcie-=c.tarcie*0.2; setPartMapping(part1,g); break;
+	case 'W': c.masa+=(2.0-c.masa)*0.3; setPartMapping(part1,g); break;
+	case 'w': c.masa+=(0.5-c.masa)*0.3; setPartMapping(part1,g); break;
+	case 'E': c.energ+=(10.0-c.energ)*0.1; setPartMapping(part1,g); break;
+	case 'e': c.energ-=c.energ*0.1;	setPartMapping(part1,g); break;
+
+	case 'D': c.cred+=(1.0-c.cred)*0.25; setPartMapping(part1,g); break;
+	case 'd': c.cred+=(0.0-c.cred)*0.25; setPartMapping(part1,g); break;
+	case 'G': c.cgreen+=(1.0-c.cgreen)*0.25; setPartMapping(part1,g); break;
+	case 'g': c.cgreen+=(0.0-c.cgreen)*0.25; setPartMapping(part1,g); break;
+	case 'B': c.cblue+=(1.0-c.cblue)*0.25; setPartMapping(part1,g); break;
+	case 'b': c.cblue+=(0.0-c.cblue)*0.25; setPartMapping(part1,g); break;
+	case 'H': c.grub+=(0.7-c.grub)*0.25; setPartMapping(part1,g); break;
+	case 'h': c.grub+=(0.05-c.grub)*0.25; setPartMapping(part1,g); break;
+
+	case '[': //neuron
+//		setdebug(g-(char*)geny,DEBUGNEURO | !l_neu);
+		if (model.getJointCount())
+			g=growNeuro(g+1,c,hasmuscles);
+		else
+			{
+			FramMessage("GenoConv_F1","grow","Illegal neuron position (ignored)",1);
+			g=skipNeuro(g+1);
+			}
+		break;
+	case 'X':
+		{
+		int freshpart=0;
+//setdebug(g-(char*)geny,DEBUGEST | !l_est);
+		if (part1<0) //initial grow
+			{
+		  if (model.getPartCount()>0)
+			    part1=0;
+		    else
+			    {
+			    part1=growPart(c,g);
+			    freshpart=1;
+			    if (first_part_mapping)
+				    model.getPart(part1)->setMapping(*first_part_mapping);
+			    }
+		  }
+		if (!freshpart)
+			{
+			Part *part=model.getPart(part1);
+			part->density=((part->mass*part->density)+1.0/c.masa)/(part->mass+1.0); // v=m*d
+//			part->volume+=1.0/c.masa;
+			part->mass+=1.0;
+			}
+		energ+=0.9*c.energ+0.1;
+		energ_div+=1.0;
+
+		int part2 = growPart(c,g);
+		growJoint(part1,part2,k,c,g);
+//		est* e = new est(*s,*s2,k,c,zz,this);
+
+		// oslabianie cech wzdluz struktury
+		c.dlug=0.5*c.dlug+0.5*stdprops.dlug;
+		c.grub=0.5*c.grub+0.5*stdprops.grub;
+		c.skr=0.66*c.skr;
+		c.rot=0.66*c.rot;
+		c.tarcie=0.8*c.tarcie+0.2*stdprops.tarcie;
+
+		c.asym=0.8*c.asym+0.2*stdprops.asym;
+		c.odpor=0.8*c.odpor+0.2*stdprops.odpor;
+		c.ruch=0.8*c.ruch+0.2*stdprops.ruch;
+		c.wchl=0.8*c.wchl+0.2*stdprops.wchl;
+		c.masa+=(stdprops.masa-c.masa)*0.5;
+		c.wykluczanie();
+	
+		if (c.resetrange) c.bendrange=1.0; else c.resetrange=1;
+		grow(part2,g+1,Pt3D_0,c);
+		return;
+		}
+	case '(':
+		{
+		setPartMapping(part1,g);
+		SList ga;
+		int i,ile;
+		ile=countBranches(g+1,ga);
+		c.resetrange=0;
+		c.bendrange=1.0/ile;
+		for (i=0;i<ile;i++)
+			grow(part1,(char*)ga(i),k+Pt3D(0,0,-3.141+(i+1)*(6.282/(ile+1))),c);
+		return;
+		}
+	case ' ': case '\t': case '\n': case '\r': break;
+	default: invalid=1; return;
+	}
+	g++;
+	}
+}
+
+SyntParam* Builder::lastNeuroClassParam()
+{
+if (!neuro_cls_param)
+	{
+	NeuroClass *cls=last_f1_neuro->getClass();
+	if (cls)
+		{
+		neuro_cls_param=new SyntParam(last_f1_neuro->classProperties());
+// this is equivalent to:
+//		SyntParam tmp=last_f1_neuro->classProperties();
+//		neuro_cls_param=new SyntParam(tmp);
+// interestingly, some compilers eliminate the call to new SyntParam,
+// realizing that a copy constructor is redundant when the original object is
+// temporary. there are no side effect of such optimization, as long as the
+// copy-constructed object is exact equivalent of the original.
+		}
+	}
+return neuro_cls_param;
+}
+
+void Builder::addClassParam(const char* name,double value)
+{
+lastNeuroClassParam();
+if (neuro_cls_param)
+	neuro_cls_param->setDoubleById(name,value);
+}
+
+void Builder::addClassParam(const char* name,const char* value)
+{
+lastNeuroClassParam();
+if (neuro_cls_param)
+	{
+	ExtValue e(value);
+	const ExtValue &re(e);
+	neuro_cls_param->setById(name,re);
+	}
+}
+
+int Builder::countBranches(const char*g,SList &out)
+{
+int gl=0;
+out+=(void*)g;
+while (gl>=0)
+	{
+	switch(*g)
+		{
+		case 0: gl=-1; break;
+		case '(': case '[': ++gl; break;
+		case ')': case ']': --gl; break;
+		case ',': if (!gl) out+=(void*)(g+1);
+		}
+	g++;
+	}
+return !out;
+}
+
+int Builder::growJoint(int part1,int part2,Pt3D &angle,F1Props &c,const char *g)
+{
+double len=min(2.0,c.dlug);
+sprintf(tmp,"j:p1=%ld,p2=%ld,dx=%lg,rx=%lg,ry=%lg,rz=%lg,stam=%lg,vr=%g,vg=%g,vb=%g",
+	part1,part2,len,angle.x,angle.y,angle.z,c.odpor, c.cred,c.cgreen,c.cblue);
+lastjoint_muscle_power=c.ruch;
+return model.singleStepBuild(tmp,makeRange(g));
+}
+
+int Builder::growPart(F1Props &c,const char *g)
+{
+sprintf(tmp,"p:m=1,dn=%lg,fr=%lg,ing=%lg,as=%lg,vs=%g,vr=%g,vg=%g,vb=%g",
+	1.0/c.masa,c.tarcie,c.wchl,c.asym, c.grub, c.cred,c.cgreen,c.cblue);
+return model.singleStepBuild(tmp,makeRange(g));
+}
+
+const char *Builder::skipNeuro(const char *z)
+{
+for (;*z;z++) if ((*z==']')||(*z==')')) break;
+return z-1;
+}
+
+const char* Builder::growNeuro(const char* t, F1Props& props,int &hasmuscles)
+{
+const char*neuroend=skipNeuro(t);
+last_f1_neuro=model.addNewNeuro();
+neuro_cls_param=NULL;
+last_f1_neuro->attachToPart(getLastPart());
+const MultiRange *mr=makeRange(t-1,neuroend+1);
+if (mr) last_f1_neuro->addMapping(*mr);
+neuro_f1_to_f0+=last_f1_neuro;
+
+SString clsname;
+bool haveclass=0;
+while(*t && *t<=' ') t++;
+const char* next=(*t)?(t+1):t;
+while(*next && *next<=' ') next++;
+if (*t && *next!=',' && *next!=']') // old style muscles [|rest] or [@rest]
+switch(*t)
+	{
+	case '@': if (t[1]==':') break;
+		haveclass=1;
+//		if (!(hasmuscles&1))
+                {
+                  hasmuscles|=1;
+		  Neuro *muscle=model.addNewNeuro();
+                  sprintf(tmp,"@:p=%lg",lastjoint_muscle_power);
+		  muscle->addInput(last_f1_neuro);
+		  muscle->setDetails(tmp);
+		  muscle->attachToJoint(getLastJoint());
+		  if (usemapping) muscle->addMapping(*makeRange(t));
+                }
+		t++;
+		break;
+	case '|': if (t[1]==':') break;
+		haveclass=1;
+//		if (!(hasmuscles&2))
+                {
+                  hasmuscles|=2;
+		  Neuro *muscle=model.addNewNeuro();
+                  sprintf(tmp,"|:p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
+		  muscle->addInput(last_f1_neuro);
+		  muscle->setDetails(tmp);
+		  muscle->attachToJoint(getLastJoint());
+		  if (usemapping) muscle->addMapping(*makeRange(t));
+                }
+		t++;
+		break;
+	}
+while(*t && *t<=' ') t++;
+bool finished=0;
+const char *begin=t;
+const char* colon=0;
+SString classparams;
+while(!finished)
+	{
+	switch (*t)
+		{
+		case ':': colon=t; break;
+		case 0: case ']': case ')': finished=1;
+			// NO break!
+		case ',':
+			if ( !haveclass && !colon && t>begin )
+				{
+				haveclass=1;
+				SString clsname(begin,t-begin);
+				clsname=trim(clsname);
+				last_f1_neuro->setClassName(clsname);
+				NeuroClass *cls=last_f1_neuro->getClass();
+				if (cls)
+					{
+					if (cls->getPreferredLocation()==2)
+						last_f1_neuro->attachToJoint(getLastJoint());
+					else if (cls->getPreferredLocation()==1)
+						last_f1_neuro->attachToPart(getLastPart());
+
+					lastNeuroClassParam();
+					//special handling: muscle properties (can be overwritten by subsequent property assignments)
+					if (!strcmp(cls->getName(),"|"))
+						{
+						neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
+						neuro_cls_param->setDoubleById("r",props.bendrange);
+						}
+					else if (!strcmp(cls->getName(),"@"))
+						{
+						neuro_cls_param->setDoubleById("p",lastjoint_muscle_power);
+						}
+					}
+				}
+			else if (colon && (colon>begin) && (t>colon))
+				growConnection(begin,colon,t,props);
+			if (t[0]!=',') t--;
+			begin=t+1; colon=0;
+			break;
+		}
+	t++;
+	}
+SAFEDELETE(neuro_cls_param);
+return t;
+}
+void Builder::growConnection(const char* begin, const char* colon,const char* end,F1Props& props)
+{
+while(*begin && *begin<=' ') begin++;
+int i;
+if (isdigit(begin[0]) || (begin[0]=='-'))
+	{
+	double weight=atof(colon+1);
+	int relative=atoi(begin);
+	int this_refno=neuro_f1_to_f0.size()-1;
+	addOrRememberInput(this_refno,this_refno+relative,weight);
+	}
+else if ((i=last_f1_neuro->extraProperties().findIdn(begin,colon-begin))>=0)
+	{
+	last_f1_neuro->extraProperties().set(i,colon+1);
+	}
+else if (isupper(begin[0]) || strchr("*|@",begin[0]))
+	{
+	SString clsname(begin,colon-begin);
+	trim(clsname);
+	Neuro *receptor=model.addNewNeuro();
+	receptor->setClassName(clsname);
+	NeuroClass *cls=receptor->getClass();
+	if (cls)
+		{
+		if (cls->getPreferredLocation()==2) receptor->attachToJoint(getLastJoint());
+		else if (cls->getPreferredLocation()==1) receptor->attachToPart(getLastPart());
+		}
+	last_f1_neuro->addInput(receptor,atof(colon+1));
+	if (usemapping) receptor->addMapping(*makeRange(begin,end-1));
+	}
+else if ((begin[0]=='>')&&(begin[1]))
+	{
+	Neuro *out=model.addNewNeuro();
+	out->addInput(last_f1_neuro,atof(colon+1));
+	out->setClassName(SString(begin+1,end-colon-1));
+	if (begin[1]=='@')
+		{
+		sprintf(tmp,"p=%lg",lastjoint_muscle_power);
+		out->setClassParams(tmp);
+		}
+	else if (begin[1]=='|')
+		{
+		sprintf(tmp,"p=%lg,r=%lg",lastjoint_muscle_power,props.bendrange);
+		out->setClassParams(tmp);
+		}
+	NeuroClass *cls=out->getClass();
+	if (cls)
+		{
+		if (cls->getPreferredLocation()==2) out->attachToJoint(getLastJoint());
+		else if (cls->getPreferredLocation()==1) out->attachToPart(getLastPart());
+		}
+	if (usemapping) out->addMapping(*makeRange(begin,end-1));
+	}
+else if (*begin=='!') addClassParam("fo",atof(colon+1));
+else if (*begin=='=') addClassParam("in",atof(colon+1));
+else if (*begin=='/') addClassParam("si",atof(colon+1));
+else if (islower(begin[0]))
+	{
+	SString name(begin,colon-begin);
+	SString value(colon+1,end-(colon+1));
+	addClassParam(name,value);
+	}
+}
Index: /cpp/frams/genetics/f1/conv_f1.h
===================================================================
--- /cpp/frams/genetics/f1/conv_f1.h	(revision 119)
+++ /cpp/frams/genetics/f1/conv_f1.h	(revision 119)
@@ -0,0 +1,81 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _CONV_F1_H
+#define _CONV_F1_H
+
+#include <frams/genetic/genoconv.h>
+#include <frams/model/model.h>
+
+struct F1Props
+{
+	double dlug,skr,masa,tarcie,ruch,asym,odpor,wchl,rot,energ;
+	double bendrange;
+	int resetrange;
+	double grub,cred,cgreen,cblue;
+	void wykluczanie();
+};
+
+/**
+ Official framsticks f1 -> f0 converter.
+ Source code is published as educational example, but currently not
+ well documented.
+ This converter features building creature using Model class
+ and some advanced tricks (changing model data during construction).
+ Final f0 genotype is generated by model class.
+
+ <b>GDK 1.0.5 NN extension: (for Framsticks 2.0)</B>
+
+ Until now, only the "standard" Framsticks v1 neuron classes could be used.
+ Starting with GDK 1.0.5 you can use all neuron types.
+
+ \b Syntax: [classname , input_or_parameter:weight , input_or_parameter:weight , ...]
+
+ The classname is optional, the default class will be used if it is omitted.
+ Note the comma after \b classname. It must be present if you provide the classname.
+ This is to distinguish between old muscle syntax and new classname specification:
+ - "[|,0:1]" is the neuron of class "|" (bend muscle) with one self connection.
+ \image html nn-ex1.gif
+ - "[|0:1]" describes the default neuron class (N) connected with the bend muscle (|).
+ \image html nn-ex2.gif
+
+
+ Neuron parameters can be specified along with inputs, eg: "[myclass,param1:34,param2:56]"
+ The names beginning with UPPER case character are assumed to be neuron classes.
+ "[myclass,g:1.23,G:2.34]" - the first 'g' is the parameter, the second one is the receptor
+ G ("gyroscope").
+
+ Another example:
+
+ "X[G][-1:2.3][-2:3.4]" - The first neuron is the standalone G receptor. Other neuron can use its output 
+ signal by specifying it as regular input ("-1:2.3" and "-2:3.4"). This NN contains 3 neurons.
+ \image html nn-ex3.gif
+
+ "X[G:2.3][G:3.4]" - with the old syntax it is impossible to connect 2 neurons with the same gyroscope,
+ because everything inside brackets is private to the neuron, others can't refer to it.
+ Adding another neuron with "G" input will add another gyroscope object. This NN contains 4 neurons
+ (or 2 neurons if you try it in Framsticks v1).
+  \image html nn-ex4.gif
+ 
+*/
+class GenoConv_F1: public GenoConverter
+{
+public:
+GenoConv_F1()
+	{
+	name="Recursive encoding";
+	in_format='1';
+	mapsupport=1;
+	}
+SString convert(SString &i,MultiMap *map);
+~GenoConv_F1() {}
+};
+
+
+#endif
+
+
+
+
+
Index: /cpp/frams/genetics/gen-config-GDK.h
===================================================================
--- /cpp/frams/genetics/gen-config-GDK.h	(revision 119)
+++ /cpp/frams/genetics/gen-config-GDK.h	(revision 119)
@@ -0,0 +1,24 @@
+// This file is a part of the Framsticks GDK library. See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+/**
+ gen-config.h
+
+ USE_GENCONV_xxx - configure converters
+ USE_GENMAN_xxx - configure genman
+
+ */
+
+#define USE_GENCONV_F10
+//#define USE_GENCONV_F21
+//#define USE_GENCONV_F30
+//#define USE_GENCONV_F40
+//#define USE_GENCONV_F41_TEST
+//#define USE_GENCONV_F50
+
+//#define USE_GENMAN_F0
+//#define USE_GENMAN_F1
+//#define USE_GENMAN_F2
+//#define USE_GENMAN_F3
+//#define USE_GENMAN_F4
+//#define USE_GENMAN_F5
Index: /cpp/frams/genetics/geno.cpp
===================================================================
--- /cpp/frams/genetics/geno.cpp	(revision 119)
+++ /cpp/frams/genetics/geno.cpp	(revision 119)
@@ -0,0 +1,274 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "geno.h"
+#include <frams/model/model.h>
+
+SListTempl<GenoValidator*> Geno::validators;
+
+void Geno::init(const SString& genstring,char genformat,const SString& genname,const SString& comment)
+{
+refcount=1;
+owner=0;
+f0gen=0;
+mapinshift=0;
+mapoutshift=0;
+isvalid=-1;
+SString gencopy(genstring);
+if (genformat==-1)
+	{ // unknown format
+	genformat='1';
+	if (genstring.charAt(0)=='/')
+		{
+		int end;
+		SString newcomment;
+		switch(genstring.charAt(1))
+			{
+			case '/':
+				genformat=genstring.charAt(2);
+				if ((end=genstring.indexOf('\n'))>=0)
+					{
+					newcomment=genstring.substr(2,end-2);
+					gencopy=genstring.substr(end+1);
+					mapinshift=end+1;
+					}
+				else
+					{
+					gencopy=0;
+					mapinshift=genstring.len();
+					}
+				break;
+			case '*':
+				genformat=genstring.charAt(2);
+				if ((end=genstring.indexOf("*/"))>=0)
+					{
+					newcomment=genstring.substr(2,end-2);
+					gencopy=genstring.substr(end+2);
+					mapinshift=end+2;
+					}
+				else
+					{
+					gencopy=0;
+					mapinshift=genstring.len();
+					}
+				break;
+			}
+		if (newcomment.len()>0)
+			{
+			SString token; int pos=0;
+			if (newcomment.getNextToken(pos,token,';'))
+			if (newcomment.getNextToken(pos,token,';'))
+				{
+				if (token.len()) txt=token;
+			if (newcomment.getNextToken(pos,token,';'))
+				if (token.len()) name=token;
+				}
+			}
+		}
+	}
+
+gen=gencopy;
+format=genformat;
+if (!name.len()) name=genname;
+if (!txt.len()) txt=comment;
+multiline=(strchr((const char*)gen,'\n')!=0);
+// mapoutshift...?
+}
+
+void Geno::freeF0()
+{
+if (f0gen) {delete f0gen; f0gen=0;}
+}
+
+Geno::Geno(const char *genstring,char genformat,const char *genname,const char *comment)
+{
+init(SString(genstring),genformat,SString(genname),SString(comment));
+}
+
+Geno::Geno(const SString& genstring,char genformat,const SString& genname,const SString& comment)
+{
+init(genstring,genformat,genname,comment);
+}
+
+Geno::Geno(const Geno& src)
+	:gen(src.gen),name(src.name),format(src.format),txt(src.txt),isvalid(src.isvalid),
+	 f0gen(0),mapinshift(src.mapinshift),mapoutshift(src.mapinshift),
+	 multiline(src.multiline),owner(0)
+{f0gen=src.f0gen?new Geno(*src.f0gen):0; refcount=1;}
+
+void Geno::operator=(const Geno& src)
+{
+freeF0();
+gen=src.gen;
+name=src.name;
+format=src.format;
+txt=src.txt;
+isvalid=src.isvalid;
+mapinshift=src.mapinshift;
+mapoutshift=src.mapinshift;
+multiline=src.multiline;
+f0gen=src.f0gen?new Geno(*src.f0gen):0;
+owner=0;
+}
+
+Geno::Geno(const SString& src)
+{
+init(src,-1,SString::empty(),SString::empty());
+}
+
+void Geno::setGene(const SString& g,char newformat)
+{
+gen=g;
+isvalid=-1;
+freeF0();
+if (newformat>=0) format=newformat;
+}
+
+void Geno::setString(const SString& g)
+{
+freeF0();
+init(g,-1,SString::empty(),SString::empty());
+}
+
+void Geno::setName(const SString& n)
+{
+name=n;
+}
+
+void Geno::setComment(const SString& c)
+{
+txt=c;
+}
+
+SString Geno::toString(void) const
+{
+SString out;
+int comment=0;
+if ((format!='1')||(comment=(txt.len()||name.len())))
+	{
+	if (multiline)
+		out+="//";
+	else
+		out+="/*";
+	out+=format;
+	if (comment)
+		{
+		if (txt.len()) {out+=";";out+=txt;}
+		if (name.len()){out+=";";out+=name;}
+		}
+	if (multiline)
+		out+="\n";
+	else
+		out+="*/";
+	}
+out+=gen;
+return out;
+}
+
+SString Geno::shortString(void) const
+{
+SString out;
+if (format!='1')
+	{
+	if (multiline)
+		out+="//";
+	else
+		out+="/*";
+	if (format==0)
+		out+="invalid";
+	else
+		out+=format;
+	if (multiline)
+		out+="\n";
+	else
+		out+="*/";
+	}
+out+=gen;
+return out;
+}
+
+int Geno::mapGenToString(int genpos) const
+{
+if (genpos>gen.len()) return -2;
+if (genpos<0) return -1;
+return mapinshift+genpos;
+}
+
+int Geno::mapStringToGen(int stringpos) const
+{
+stringpos-=mapinshift;
+if (stringpos>gen.len()) return -2;
+if (stringpos<0) return -1;
+return stringpos;
+}
+
+SString Geno::getGene(void) const {return gen;}
+SString Geno::getName(void) const {return name;}
+char Geno::getFormat(void) const {return format;}
+SString Geno::getComment(void) const {return txt;}
+
+class ModelGenoValidator: public GenoValidator
+{
+public:
+	ModelGenoValidator();
+	int testGenoValidity(Geno& g);
+};
+
+ModelGenoValidator::ModelGenoValidator()
+{
+Geno::validators+=this;
+}
+
+int ModelGenoValidator::testGenoValidity(Geno& g)
+{
+if (g.getFormat()=='0')
+	{
+	Model mod(g);
+	return mod.isValid();
+	}
+else
+	{
+	Geno f0geno=g.getConverted('0');
+	return f0geno.isValid();
+	}
+}
+
+static ModelGenoValidator default_validator;
+
+void Geno::validate()
+{
+if (isvalid>=0) return;
+if (gen.len()==0) { isvalid=0; return; }
+FOREACH(GenoValidator*,v,validators)
+	if ((isvalid=v->testGenoValidity(*this))>=0)
+		break;
+}
+
+bool Geno::isValid(void)
+{
+if (isvalid<0) validate();
+return isvalid>0;
+}
+
+Geno Geno::getConverted(char otherformat,MultiMap *m)
+{
+if (otherformat==getFormat()) return *this;
+#ifndef NO_GENOCONVMANAGER
+if ((otherformat=='0')&&(!m))
+	{
+	if (!f0gen)
+		f0gen=new Geno(GenoConvManager::globalConvert(*this,otherformat));
+	return *f0gen;
+	}
+else
+	return GenoConvManager::globalConvert(*this,otherformat,m);
+#else
+return (otherformat==getFormat())?*this:Geno(0,0,0,"GenConvManager not available");
+#endif
+}
+
+Geno::~Geno()
+{
+if (f0gen) delete f0gen;
+}
Index: /cpp/frams/genetics/geno.h
===================================================================
--- /cpp/frams/genetics/geno.h	(revision 119)
+++ /cpp/frams/genetics/geno.h	(revision 119)
@@ -0,0 +1,112 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _GENO_H_
+#define _GENO_H_
+
+#include <frams/util/sstring.h>
+#include <frams/util/extvalue.h>
+
+class MultiMap;
+class Geno;
+
+class GenoValidator
+{
+  public:
+virtual int testGenoValidity(Geno& g)=0;/// -1=no information  0=invalid  1=valid
+};
+
+/// basic information about a single genotype.
+class Geno: public DestrBase
+{
+SString gen;
+SString name;
+char format;
+SString txt;
+int isvalid; ///< <0 -> unknown   >=0 -> value for "isValid"
+
+Geno *f0gen;
+
+int mapinshift; /// # of characters in the initial comment
+int mapoutshift; /// # of characters in the output comment
+int multiline;
+
+void init(const SString& genstring,char genformat,const SString& genname,const SString& comment);
+void validate(void);
+
+void freeF0();
+
+bool isInvalid() {return isvalid==0;}
+
+friend class Model;
+friend class GenoConvManager;
+	
+public:
+/// create a genotype object from primitives
+/// @param genstring pure genotype, without any comments
+/// @param genformat genotype format
+/// @param comment information about genotype (for genetic operators and "history")
+Geno(const char *genstring=0,char genformat=-1,const char *genname=0,const char *comment=0);
+
+/// create a genotype object from primitives
+/// @param genstring pure genotype, wihtout any comments
+/// @param genformat genotype format
+/// @param name genotype name, new name will generated if needed
+/// @param comment information about genotype (for genetic operators and "history")
+Geno(const SString& genstring,char genformat,const SString& genname,const SString& comment);
+
+/// create object from full string, containing optional format and comment information
+Geno(const SString & fullstring);
+
+/// clone
+Geno(const Geno& src);
+
+void operator=(const Geno& src);
+
+~Geno();
+
+void setValid(int v) {isvalid=v;}
+int getValid() {return isvalid;}
+
+/// return string representation, with format comment at the beginning
+SString toString(void) const;
+SString shortString(void) const;
+
+void setString(const SString& genewithcomments);
+
+/** @param newformat=-1 -> don't change */
+void setGene(const SString& g, char newformat=-1);
+SString getGene(void) const;
+
+SString getName(void) const;
+void setName(const SString&);
+char getFormat(void) const;
+
+SString getComment(void) const;
+void setComment(const SString&);
+
+/// invalid genotype cannot be used to build a creature
+bool isValid(void);
+
+/// make converted version of the genotype.
+Geno getConverted(char otherformat,MultiMap *m=0);
+
+/// @return -1 = before first char in the string
+/// @return -2 = after last char in the string
+int mapGenToString(int genpos) const;
+/// @return -1 = before first char in the genotype
+/// @return -2 = after last char in the genotype
+int mapStringToGen(int stringpos) const;
+
+int operator==(const Geno &g) {return (format==g.format)&&(gen==g.gen);}
+
+void* owner;
+static SListTempl<GenoValidator*> validators;
+};
+
+#ifndef NO_GENOCONVMANAGER
+#include "genoconv.h"
+#endif
+
+#endif
Index: /cpp/frams/genetics/genoconv.cpp
===================================================================
--- /cpp/frams/genetics/genoconv.cpp	(revision 119)
+++ /cpp/frams/genetics/genoconv.cpp	(revision 119)
@@ -0,0 +1,227 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include <common/nonstd.h>
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <errno.h>
+
+#include "genoconv.h"
+#include <frams/util/multimap.h>
+
+///////////////////////////////////////////////////////////////////////////
+
+GenoConvParam::GenoConvParam(GenoConvManager *g):Param(0),gcm(g)
+{
+updatetab();
+}
+
+void GenoConvParam::freetab()
+{
+if (tab) free(tab);
+tab=0;
+}
+
+const char *GenoConvParam::id(int i)
+{
+if (i>=gcm->converters.size()) return 0;
+sprintf(tmp_id,"genkonw%d",i);
+return tmp_id;
+}
+
+void GenoConvParam::updatetab()
+{
+int i;
+GenoConverter *gk;
+ParamEntry *pe;
+int ile=gcm->converters.size();
+freetab();
+tab=(ParamEntry*)calloc(2+ile,sizeof(ParamEntry));
+tab[0].id="Genetics: Conversions";
+tab[0].group=1;
+tab[0].flags=(short)ile;
+tab[0].name="gkparam:";
+gcnames.clear();
+for (i=0,pe=tab+1;gk=(GenoConverter *)gcm->converters(i);pe++,i++)
+	{
+	pe->id="?";
+	pe->group=0;
+	pe->flags=0;
+	std::string descr="f";
+	descr+=gk->in_format;
+	descr+=" -> f";
+	descr+=gk->out_format;
+	descr+=" : ";
+	descr+=gk->name;
+	gcnames.push_back(descr);
+	pe->name=descr.c_str();
+	pe->type="d 0 1";
+	pe->help=gk->info;
+	}
+pe->id=0;
+}
+
+GenoConvParam::~GenoConvParam()
+{
+freetab();
+}
+
+void *GenoConvParam::getTarget(int i)
+{
+GenoConverter *gk=(GenoConverter *)gcm->converters(i);
+return &gk->enabled;
+}
+
+GenoConvManager::GenoConvManager()
+	:param(this)
+{
+if (!globalobject) globalobject=this;
+}
+
+GenoConvManager::~GenoConvManager()
+{
+GenoConverter *gc;
+for (converters.start();gc=(GenoConverter*)converters();) delete gc;
+if (globalobject==this) globalobject=NULL;
+}
+
+GenoConvManager *GenoConvManager::globalobject=NULL;
+
+void GenoConvManager::addConverter(GenoConverter *gc)
+{
+converters+=gc;
+param.updatetab();
+}
+void GenoConvManager::removeConverter(GenoConverter *gc)
+{
+converters-=gc;
+param.updatetab();
+}
+
+GenoConverter *GenoConvManager::findConverters(SListTempl<GenoConverter*>* result,char in,char out,int enabled,char* name)
+{
+GenoConverter *gk,*retval=0;
+int i=0;
+for (;gk=(GenoConverter*)converters(i);i++)
+	{
+	if ((in!=-1)&&(in!=gk->in_format)) continue;
+	if ((out!=-1)&&(out!=gk->out_format)) continue;
+	if ((enabled!=-1)&&(enabled!=gk->enabled)) continue;
+	if ((name)&&(strcmp(name,gk->name))) continue;
+	if (!retval) {retval=gk; if (!result) break;}
+	if (result) result->append(gk);
+	}
+return retval;
+}
+
+/// write path into 'path'
+/// return the last path element (return >= path)
+/// null -> path not found
+/// @param mapavailable will receive 1 if conversion map is supported by all converters in path
+/// (can be NULL if you don't need this information)
+
+char *GenoConvManager::getPath(char in,char out,char *path,int maxlen,int *mapavailable)
+{
+if (!maxlen) return 0;
+GenoConverter *gk;
+int i=0;
+for (;gk=(GenoConverter*)converters(i);i++)
+	{
+	if ((gk->enabled)&&(gk->in_format == in))
+		{
+		*path=(char)i;
+		if (gk->out_format == out)
+			{
+			if (mapavailable)
+				*mapavailable=gk->mapsupport;
+			return path;
+			}
+		else
+			{
+			int mapavail;
+			char *ret=getPath(gk->out_format,out,path+1,maxlen-1,&mapavail);
+			if (ret)
+				{
+				if (mapavailable)
+					*mapavailable=gk->mapsupport && mapavail;
+				return ret;
+				}
+			}
+		}
+	}
+return 0;
+}
+
+char *GenoConvManager::getFormatPath(char in,char out,char *path,int maxlen,int *mapavailable)
+{
+char *ret=getPath(in,out,path,maxlen,mapavailable);
+if (ret)
+	{
+	for (char*t=path;t<=ret;t++)
+		*t=((GenoConverter*)converters(*t))->out_format;
+	}
+return ret;
+}
+
+Geno GenoConvManager::convert(Geno &in,char format,MultiMap *map)
+{
+if (in.getFormat()==format) return in;
+char path[10];
+int dep;
+char *ret;
+if (in.isInvalid()) { return Geno("",0,"","invalid genotype cannot be converted"); }
+int mapavail;
+for (dep=1;dep<(int)sizeof(path);dep++) // sogenannte iteracyjne poglebianie...
+	if (ret=getPath(in.getFormat(),format,path,dep,&mapavail)) break;
+if (!ret) { return Geno("",0,"","converter not found"); }
+if (!map) mapavail=0;
+char *t=path;
+SString tmp;
+tmp=in.getGene();
+MultiMap lastmap,tmpmap;
+int firstmap=1;
+for (;t<=ret;t++)
+	{
+	GenoConverter *gk=(GenoConverter*)converters(*t);
+	tmp=gk->convert(tmp,mapavail?&tmpmap:0);
+	if (!tmp.len())
+		{
+		char t[100];
+		sprintf(t,"f%c->f%c conversion failed (%s)",gk->in_format,gk->out_format,gk->name);
+		return Geno(0,0,0,t);
+		}
+	if (mapavail)
+		{
+		if (firstmap)
+			{
+			lastmap=tmpmap;
+			firstmap=0;
+			}
+		else
+			{
+			MultiMap m;
+			m.addCombined(lastmap,tmpmap);
+			lastmap=m;
+			}
+		tmpmap.clear();
+		}
+	}
+if (map)
+	*map=lastmap;
+return Geno(tmp, format, in.getName(), in.getComment());
+}
+
+Geno GenoConvManager::globalConvert(Geno &in,char format,MultiMap *map)
+{
+if (globalobject) return globalobject->convert(in,format,map);
+if (format==in.getFormat()) return in;
+return Geno(0,0,0,"GenConvManager not initialized");
+}
+
+/////////////////////////////////
Index: /cpp/frams/genetics/genoconv.h
===================================================================
--- /cpp/frams/genetics/genoconv.h	(revision 119)
+++ /cpp/frams/genetics/genoconv.h	(revision 119)
@@ -0,0 +1,104 @@
+// This file is a part of the Framsticks GDK library.
+// Copyright (C) 2002-2011  Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _GENCONV_H_
+#define _GENCONV_H_
+
+#include "geno.h"
+#include <frams/param/param.h>
+#include <frams/util/list.h>
+#include <frams/util/sstring.h>
+
+#include <string>
+#include <vector>
+
+
+class GenoConvManager;
+
+class GenoConvParam: public Param
+{
+GenoConvManager *gcm;
+std::vector<std::string> gcnames;
+char tmp_id[20];
+void freetab();
+public:
+GenoConvParam(GenoConvManager *g);
+~GenoConvParam();
+void *getTarget(int);
+const char* id(int i);
+void updatetab();
+};
+
+class MultiMap;
+
+/// Base class for all Geno Converters.
+/// In constructor you have to set public fields
+/// indicating your identity and supported formats.
+/// Each converter serves one in-out format pair.
+/// Instance of your converter should be registered
+/// in GenoConvManager.
+class GenoConverter
+{
+public:
+const char *name;	//< converter name (short)
+char in_format,		//< input format, eg. '1'
+	out_format;	//< output format, eg. '0'
+const char *info;	//< detailed info about converter, format or copyright
+long enabled;	//< don't touch this! (used by configuration module)
+long mapsupport; //< set to 1 if your converter supports genotype mapping
+
+/// You have to reimplement this method.
+/// If your converter cannot do its job, return empty string
+/// (return SString();), any other return value is assumed
+/// to be output genotype.
+/// @param map if not null, mapping informaton is requested, converter should add conversion map to this object
+virtual SString convert(SString &i,MultiMap *map) {return SString();}
+
+virtual ~GenoConverter() {}
+/// Don't forget to set public fields in your constructor
+GenoConverter():name(""),in_format(-1),out_format('0'),info(""),enabled(1),mapsupport(0) {}
+};
+
+/// This class gathers abilities of all converters and can
+/// convert a genotype to any other one, provided there is
+/// a path of GenoConverters between them.
+/// In most cases you don't use this class directly,
+/// Geno::getConverted(int) provides full converting functionality.
+/// Explicit GenoConvManager object is only needed for registering
+/// your GenoConverter.
+/// Use DefaultGenoConvManager to register the standard genotype converters automatically.
+class GenoConvManager
+{
+friend class GenoConvParam;
+SList converters;
+static GenoConvManager *globalobject;
+public:
+GenoConvManager();
+~GenoConvManager();
+class GenoConvParam param;
+/// select an object for use as global GenoConvManager
+void useManager(GenoConvManager *m) {globalobject=m;}
+/// get global converter
+static GenoConvManager *getGlobalObject() {return globalobject;}
+/// make a genotype in other format. genotype will be invalid
+/// if GenoConvManager cannot convert it.
+Geno convert(Geno &in,char format,MultiMap *map=0);
+/// static conversion function (uses global GenoConvManager)
+static Geno globalConvert(Geno &in,char format,MultiMap *map=0);
+/// register GenoConverter
+void addConverter(GenoConverter *conv);
+/// unregister GenoConverter
+void removeConverter(GenoConverter *conv);
+
+char *getPath(char in,char out,char *path,int maxlen,int *mapavailable=0);
+char *getFormatPath(char in,char out,char *path,int maxlen,int *mapavailable=0);
+/// returns the list of converters meeting the specified criteria
+/// pass result=0 if you only need one result (by return value)
+/// default criteria values mean "don't care", pass anything else to narrow your search
+GenoConverter *findConverters(SListTempl<GenoConverter*>* result=0,char in=-1,char out=-1,int enabled=-1,char* name=0);
+};
+
+#endif
+
+
Index: /cpp/frams/genetics/oper_fx.cpp
===================================================================
--- /cpp/frams/genetics/oper_fx.cpp	(revision 119)
+++ /cpp/frams/genetics/oper_fx.cpp	(revision 119)
@@ -0,0 +1,244 @@
+// This file is a part of the Framsticks GenoFX library.
+// Copyright (C) 2002-2011  Maciej Komosinski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include <ctype.h>  //isupper()
+#include "geno_fx.h"
+#include <common/framsg.h>
+#include <common/nonstd_math.h>
+#include <frams/util/rndutil.h>
+
+static double distrib_force[]=   // for '!'
+{
+3,                 // distribution 0 -__/ +1
+0.001, 0.2,        // "slow" neurons
+0.001, 1,
+    1, 1,          // "fast" neurons
+};
+static double distrib_inertia[]=  // for '='
+{
+2,                 // distribution 0 |..- +1
+  0, 0,            // "fast" neurons
+0.7, 0.98,
+};
+static double distrib_sigmo[]=  // for '/'
+{
+5,                 // distribution -999 -..-^-..- +999
+-999, -999,        //"perceptron"
+ 999, 999,
+  -5, -1,          // nonlinear
+   1, 5,
+  -1, 1,           // ~linear
+};
+
+
+int Geno_fx::roulette(const double *probtab,const int count)
+{
+   double sum=0;
+   int i;
+   for (i=0;i<count;i++) sum+=probtab[i];
+   double sel=rnd01*sum;
+   for (sum=0,i=0;i<count;i++) {sum+=probtab[i]; if (sel<sum) return i;}
+   return -1;
+}
+
+bool Geno_fx::getMinMaxDef(ParamInterface *p,int i,double &mn,double &mx,double &def)
+{
+   mn=mx=def=0;
+   int defined=0;
+   if (p->type(i)[0]=='f')
+   {
+      double _mn=0,_mx=1,_def=0.5;
+      defined=p->getMinMax(i,_mn,_mx,_def);
+      if (defined==1) _mx=_mn+1.0;
+      if (_mx<_mn && defined==3) _mn=_mx=_def; //only default was defined, let's assume min=max=default
+      if (defined<3) _def=(_mn+_mx)/2.0;
+      mn=_mn; mx=_mx; def=_def;
+   }
+   if (p->type(i)[0]=='d')
+   {
+      long _mn=0,_mx=1,_def=0;
+      defined=p->getMinMax(i,_mn,_mx,_def);
+      if (defined==1) _mx=_mn+1;
+      if (_mx<_mn && defined==3) _mn=_mx=_def; //only default was defined, let's assume min=max=default
+      if (defined<3) _def=(_mn+_mx)/2;
+      mn=_mn; mx=_mx; def=_def;
+   }
+   return defined==3;
+}
+
+int Geno_fx::selectRandomProperty(Neuro* n)
+{
+   int neuext=n->extraProperties().getPropCount(),
+       neucls=n->getClass()==NULL?0:n->getClass()->getProperties().getPropCount();
+   if (neuext+neucls==0) return -1; //no properties in this neuron
+   int index=randomN(neuext+neucls);
+   if (index>=neuext) index=index-neuext+100;
+   return index;
+}
+
+double Geno_fx::mutateNeuProperty(double current,Neuro *n,int i)
+{
+   if (i==-1) return mutateCreepNoLimit('f',current,-10,10); //i==-1: mutating weight of neural connection
+   Param p;
+   if (i>=100) {i-=100; p=n->getClass()->getProperties();}
+      else p=n->extraProperties();
+   double newval=current;
+   /*bool ok=*/getMutatedProperty(p,i,current,newval);
+   return newval;
+}
+
+bool Geno_fx::mutatePropertyNaive(ParamInterface &p,int i)
+{
+   double mn,mx,df;
+   if (p.type(i)[0]!='f' && p.type(i)[0]!='d') return false; //don't know how to mutate
+   getMinMaxDef(&p,i,mn,mx,df);
+
+   ExtValue ev;
+   p.get(i,ev);
+   ev.setDouble(mutateCreep(p.type(i)[0],ev.getDouble(),mn,mx));
+   p.set(i,ev);
+   return true;
+}
+
+bool Geno_fx::mutateProperty(ParamInterface &p,int i)
+{
+   double newval;
+   ExtValue ev;
+   p.get(i,ev);
+   bool ok=getMutatedProperty(p,i,ev.getDouble(),newval);
+   if (ok) {ev.setDouble(newval); p.set(i,ev);}
+   return ok;
+}
+
+bool Geno_fx::getMutatedProperty(ParamInterface &p,int i,double oldval,double &newval)
+{
+   newval=0;
+   if (p.type(i)[0]!='f' && p.type(i)[0]!='d') return false; //don't know how to mutate
+   const char *n=p.id(i),*na=p.name(i);
+     if (strcmp(n,"si")==0 && strcmp(na,"Sigmoid")==0) newval=CustomRnd(distrib_sigmo); else
+     if (strcmp(n,"in")==0 && strcmp(na,"Inertia")==0) newval=CustomRnd(distrib_inertia); else
+     if (strcmp(n,"fo")==0 && strcmp(na,"Force")==0) newval=CustomRnd(distrib_force); else
+     {
+       double mn,mx,df;
+       getMinMaxDef(&p,i,mn,mx,df);
+       newval=mutateCreep(p.type(i)[0],oldval,mn,mx);
+     }
+   return true;
+}
+
+double Geno_fx::mutateCreepNoLimit(char type,double current,double mn,double mx)
+{
+   double result=RndGen.Gauss(current,(mx-mn)/2/5); // /halfinterval, 5 times narrower
+   if (type=='d') {result=int(result+0.5); if (result==current) result+=randomN(2)*2-1;}
+    else result=floor(result*1000+0.5)/1000.0; //round
+   return result;
+}
+
+double Geno_fx::mutateCreep(char type,double current,double mn,double mx)
+{
+   double result=mutateCreepNoLimit(type,current,mn,mx); //TODO consider that when boundary is touched (reflect/absorb below), the default precision (3 digits) may change. Is it good or bad?
+   //reflect:
+   if (result>mx) result=mx-(result-mx); else
+    if (result<mn) result=mn+(mn-result);
+   //absorb (just in case 'result' exceeded the allowed range so much):
+   if (result>mx) result=mx; else
+    if (result<mn) result=mn;
+   return result;
+}
+
+NeuroClass* Geno_fx::getRandomNeuroClass()
+{
+	SListTempl<NeuroClass*> active;
+   for(int i=0;i<Neuro::getClassCount();i++)
+      if (Neuro::getClass(i)->genactive) active+=Neuro::getClass(i);
+   if (!active==0) return NULL; else return active(randomN(!active));
+}
+
+NeuroClass* Geno_fx::parseNeuroClass(char*& s)
+{
+   int len=strlen(s);
+   int Len=0;
+   NeuroClass *I=NULL;
+   for(int i=0;i<Neuro::getClassCount();i++)
+   {
+      const char *n=Neuro::getClass(i)->name;
+      int l=strlen(n);
+      if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=Neuro::getClass(i); Len=l;}
+   }
+   s+=Len;
+   return I;
+}
+
+Neuro* Geno_fx::findNeuro(const Model *m,const NeuroClass *nc)
+{
+  if (!m) return NULL;
+  for(int i=0;i<m->getNeuroCount();i++)
+     if (m->getNeuro(i)->getClass()==nc) return m->getNeuro(i);
+  return NULL; //neuron of class 'nc' was not found
+}
+
+int Geno_fx::neuroClassProp(char*& s,NeuroClass *nc,bool also_v1_N_props)
+{
+   int len=strlen(s);
+   int Len=0,I=-1;
+   if (nc)
+   {
+      Param p=nc->getProperties();
+      for(int i=0;i<p.getPropCount();i++)
+      {
+         const char *n=p.id(i);
+         int l=strlen(n);
+         if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=100+i; Len=l;}
+         if (also_v1_N_props) //recognize old properties symbols /=!
+         {
+            if (strcmp(n,"si")==0) n="/"; else
+            if (strcmp(n,"in")==0) n="="; else
+            if (strcmp(n,"fo")==0) n="!";
+            l=strlen(n);
+            if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=100+i; Len=l;}
+         }
+      }
+   }
+   Neuro n;
+   Param p=n.extraProperties();
+   for(int i=0;i<p.getPropCount();i++)
+   {
+      const char *n=p.id(i);
+      int l=strlen(n);
+      if (len>=l && l>Len && (strncmp(s,n,l)==0)) {I=i; Len=l;}
+   }
+   s+=Len;
+   return I;
+}
+
+bool Geno_fx::isWS(const char c)
+{return c==' ' || c=='\n' || c=='\t' || c=='\r';}
+
+void Geno_fx::skipWS(char *&s)
+{ if (!s) FramMessage("Geno_fx","skipWS","NULL reference!",1); else
+     while (isWS(*s)) s++;
+}
+
+bool Geno_fx::areAlike(char *g1,char *g2)
+{
+	while (*g1 || *g2)
+	{
+		skipWS(g1);
+		skipWS(g2);
+		if (*g1 != *g2) return false; //when difference
+      if (!*g1 && !*g2) break; //both end
+      g1++;
+      g2++;
+	}
+	return true; //equal
+}
+
+char* Geno_fx::strchrn0(const char *str,char ch)
+{ return ch==0?NULL:strchr((char*)str,ch); }
+
+bool Geno_fx::isNeuroClassName(const char firstchar)
+{
+   return isupper(firstchar) || firstchar=='|' || firstchar=='@' || firstchar=='*';
+}
+
Index: /cpp/frams/genetics/oper_fx.h
===================================================================
--- /cpp/frams/genetics/oper_fx.h	(revision 119)
+++ /cpp/frams/genetics/oper_fx.h	(revision 119)
@@ -0,0 +1,218 @@
+// This file is a part of the Framsticks GenoFX library.
+// Copyright (C) 2002-2011  Maciej Komosinski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _GENO_FX_H_
+#define _GENO_FX_H_
+
+#include <common/nonstd.h>
+#include <frams/model/model.h>
+
+/** @file */
+
+/** \name Return codes for genetic operators */
+//@{
+#define GENOPER_OK          0 ///<operation successful
+#define GENOPER_OPFAIL     -1 ///<operation failed or could not be completed
+#define GENOPER_REPAIR     -2 ///<do not use in Geno_fx. GenMan uses it in checkValidity()... but will not. only f4 uses it
+#define GENOPER_NOOPER     -3 ///<do not use in Geno_fx. GenMan uses it for "no suitable operator for this genotype format"
+//@}
+
+/** \name gene/character predefined styles (for style() method) */
+//@{
+#define GENSTYLE_NONE       0 ///<no style specified (=normal font)
+#define GENSTYLE_INVALID    1 ///<this char cannot be accepted
+#define GENSTYLE_BOLD       2 ///<bold
+#define GENSTYLE_ITALIC     4 ///<italic
+#define GENSTYLE_STRIKEOUT  8 ///<strikeout (not recommended)
+//UNDERLINE used to mark errors
+//@}
+
+/** \name other useful style/color macros */
+//@{
+#define GENRGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16)))
+#define GENSTYLE_RGBS(r,g,b,s) ((unsigned long)((unsigned char)s)<<24 | GENRGB(r,g,b))
+#define GENSTYLE_CS(rgb,s) ((unsigned long)((unsigned char)s)<<24 | rgb)
+
+#define GENGETSTYLE(style) ((style)>>24)
+#define GENGETCOLOR(style) ((style)&0x00ffffff)
+#define GENGET_R(style) ((style)&0xff)
+#define GENGET_G(style) ((style>>8)&0xff)
+#define GENGET_B(style) ((style>>16)&0xff)
+
+#define GENCOLOR_TEXT    GENRGB(0,0,0) ///<recommended color to use for text genes
+#define GENCOLOR_NUMBER  GENRGB(200,0,0) ///<recommended color to use for number genes
+//@}
+
+///Base class for genetic operations on genotypes of some genetic format
+/**\author Maciej Komosinski
+
+When designing genetic operations on some representation, inherit your class
+(for example Geno_fMy) from Geno_fx. Define some methods,
+like mutate(), in your class, to allow for evolution.
+Ensure they have the same names and arguments as the corresponding
+virtual methods in Geno_fx. Set the 'supported_format' variable to the
+appropriate genetic representation ID.
+Whenever arguments are genotypes, they are without
+trailing characters which describe genetic format
+(for example, "p:", not "//0\np:").
+When allocating/reallocating char* parameters, use malloc, free, realloc, strdup, etc.
+Do not use new and delete.
+
+All the methods you might define are:
+- checkValidity()
+- validate()
+- mutate()
+- crossOver()
+- getSimplest()
+- style()
+
+Your code must not cause errors (like invalid memory access, memory
+leaks) on any arguments, even 'random' ones. GENOPER_OPFAIL should
+be returned when an operator cannot cope with its argument genotype.
+
+To compile your code, you may also need some GDK files.
+A simple example is Geno_ftest class (see \ref geno_ftest_example "C++ code" for details).
+A more realistic example is Geno_f4 derived from Geno_fx: refer to
+the available source on developmental encoding and f4 genotype format.*/
+
+class Geno_fx
+{
+ public:
+   Param par;
+   char supported_format; ///<genotype format which is supported by this class ('6' for Geno_f6, etc.). Must be initialized in constructor
+   SString name; ///<name of this set of genetic operators
+   char **mutation_method_names; ///<array of names for mutation methods. If initialized (by new char*[]), must have entries for each method index returned by mutate(geno,chg,METHOD).  If initialized, it is automatically freed by this destructor.
+   Geno_fx() : par(empty_paramtab) {supported_format='x'; name="Default"; mutation_method_names=NULL; setDefaults();}
+
+/**Used to perform initializations of Param parameters that are not handled by the Param itself
+(i.e. string parameters need to be initialized here)*/
+   virtual void setDefaults() {}
+
+/**Checks a genotype for minor mistakes and major errors.
+\param geno genotype to be checked
+\retval error_position 1-based (or 1 if no exact error position known)
+\retval GENOPER_OK when the genotype is fully valid, and can be translated by the converter with \b no modifications nor tweaks*/
+   virtual int checkValidity(const char *geno) {return GENOPER_NOOPER;}
+
+/**Validates a genotype. The purpose of this function is to validate
+obvious/minor errors (range overruns, invalid links, etc.). Do not try
+to introduce entirely new genes in place of an error.
+\param geno input/output: genotype to be validated
+\retval GENOPER_OK must be returned in any case ("did my best to validate")*/
+   virtual int validate(char *&geno) {return GENOPER_NOOPER;}
+
+/**Mutates a genotype. Mutation should always change something.
+
+Avoid unnecessary calls in your code. Every genotype argument passed to this
+function is first checked, and validated if checkValidity() reported an error (or
+if there is no checkValidity() implemented). Every resulting genotype is subject
+to the same procedure, unless GENOPER_OPFAIL was returned. Thus you do not have
+to call these functions on input and output genotypes, because they are validated
+if needed.
+\param geno input/output: genotype to be mutated
+\param chg output: initialize with a value (in most cases 0..1) corresponding
+to the amount of genotype mutated. For example, it could be the number of changed
+genes divided by the total number of genes before mutation.
+\param chg method: initialize with the ID (number) of mutation method used.
+\retval GENOPER_OK
+\retval GENOPER_OPFAIL
+\sa
+Mutation example to illustrate the exchange of pointers for \e geno.
+The mutation adds random letter at the beginning or removes last letter from \e geno.
+\code
+{
+ int len=strlen(geno);
+ if (len==0 || random(2)==0) //add
+ {
+    method=0;
+    char* mutated=(char*)malloc(mutated,len+2); //allocate for mutated genotype
+    mutated[0]='A'+random(10); //first char random
+    strcpy(mutated+1,geno); //the rest is original
+    free(geno); //must take care of the original allocation
+    geno=mutated;
+ } else 
+ {
+    method=1;
+    geno[len-1]=0; //simply shorten the string - remove last char
+ }
+ chg=1.0/max(len,1); //estimation of mutation strength, divby0-safe
+} \endcode
+*/
+   virtual int mutate(char *&geno,float& chg,int &method) {method=-1; chg=-1; return GENOPER_NOOPER;}
+
+/**Crosses over two genotypes. It is sufficient to return only one child (in \e g1) and set \e chg1 only, then \e g2 must equal "".
+
+Avoid unnecessary calls in your code. Every genotype argument passed to this
+function is first checked, and validated if checkValidity() reported an error (or
+if there is no checkValidity() implemented). Every resulting genotype is subject
+to the same procedure, unless GENOPER_OPFAIL was returned. Thus you do not have
+to call these functions on input and output genotypes, because they are validated
+if needed.
+\param g1 input/output: parent1 genotype, initialize with child1
+\param g2 input/output: parent2 genotype, initialize with child2 if both children are available
+\param chg1 output: initialize with the fraction of parent1 genes in child1 (parent2 has the rest)
+\param chg2 output: initialize with the fraction of parent2 genes in child2 (parent1 has the rest)
+\retval GENOPER_OK
+\retval GENOPER_OPFAIL
+\sa mutate() for an example*/
+   virtual int crossOver(char *&g1,char *&g2,float& chg1,float& chg2) {chg1=chg2=-1; return GENOPER_NOOPER;}
+
+/**\return a pointer to the simplest genotype string*/
+   virtual char* getSimplest() {return NULL;}
+
+/**You may want to have your genotype colored. This method provides desired character styles for genes.
+\param geno genotype
+\param pos 0-based char offset
+\retval number-encoded visual style (and validity) of the genotype char at \e geno[pos].
+Assume white background.
+\sa GENSTYLE_* macros, like GENSTYLE_BOLD*/
+   virtual unsigned long style(const char *geno,int pos) {return GENSTYLE_RGBS(0,0,0,GENSTYLE_NONE);}
+
+///currently not used (similarity of two genotypes)
+   virtual float similarity(const char*,const char*) {return GENOPER_NOOPER;}
+   virtual ~Geno_fx() {if (mutation_method_names) {delete []mutation_method_names; mutation_method_names=NULL;}}
+//   virtual char getFormat() {return 255;} //returns supported genotype format, for ex. '1'
+//   virtual int enabled() {return 1;} // should be enabled by default
+
+/** \name Some helpful methods for you */
+//@{
+	 static int roulette(const double *probtab,const int count); 	///<returns random index according to probabilities in the \e probtab table or -1 if all probs are zero. \e count is the number of elements in \e probtab.
+   static bool getMinMaxDef(ParamInterface *p,int propindex,double &mn,double &mx,double &def); ///<perhaps a more useful (higher-level) way to obtain min/max/def info for integer and double properties. Returns true if min/max/def was really available (otherwise it is just invented).
+   static int selectRandomProperty(Neuro* n); ///<selects random property (either 0-based extraproperty of Neuro or 100-based property of its NeuroClass). -1 if Neuro has no properties.
+   static double mutateNeuProperty(double current,Neuro *n,int propindex); ///<returns value \e current mutated for the property \e propindex of NeuroClass \e nc or for extraproperty (\e propindex - 100) of Neuro. Neuro is used as read-only. Give \e propindex == -1 to mutate connection weight (\e nc is then ignored).
+   static bool mutatePropertyNaive(ParamInterface &p,int propindex); ///<creep-mutate selected property. Returns true when success. mutateProperty() should be used instead of this function.
+   static bool mutateProperty(ParamInterface &p,int propindex); ///<like mutatePropertyNaive(), but uses special probability distributions for some neuron properties.
+   static bool getMutatedProperty(ParamInterface &p,int i,double oldval,double &newval); ///<like mutateProperty(), but just returns \e newval, does not get nor set it using \e p.
+   static double mutateCreepNoLimit(char type,double current,double mn,double mx); ///<returns \e current value creep-mutated with Gaussian distribution within [ \e mn , \e mx ] interval. Forced precision: 3 digits after comma. \e type must be either 'd' (integer) or 'f' (float/double).
+   static double mutateCreep(char type,double current,double mn,double mx); ///<just as mutateCreepNoLimit(), but forces mutated value into the [mn,mx] range using the 'reflect' approach.
+   static NeuroClass* getRandomNeuroClass(); ///<returns random neuroclass or NULL when no active classes.
+   static NeuroClass* parseNeuroClass(char *&s); ///<returns neuroclass or NULL if the string does not begin with a valid name. Advance \e s pointer.
+   static Neuro* findNeuro(const Model *m,const NeuroClass *nc); ///<returns pointer to first Neuro of class \e nc, or NULL if there is no such Neuro.
+   static int neuroClassProp(char *&s,NeuroClass *nc,bool also_v1_N_props=false); ///<returns 0-based property number for \e neuroclass, 100-based extraproperty number for Neuro, or -1 if the string does not begin with a valid property name. Advance \e s pointer if success.
+   static bool isWS(const char c); ///<is \e c a whitespace char?
+   static void skipWS(char *&s); ///<advances pointer \e s skipping whitespaces.
+   static bool areAlike(char*,char*); ///<compares two text strings skipping whitespaces. Returns 1 when equal, 0 when different.
+ 	 static char* strchrn0(const char *str,char ch); ///<like strchr, but does not find zero char in \e str.
+   static bool isNeuroClassName(const char firstchar); ///<determines if \e firstchar may start NeuroClass name. If not, it may start NeuroClass' (or Neuro's) property name.
+//@}
+};
+
+
+//
+// custom distributions for mutations of various parameters
+//
+/*
+static double distrib_weight[]=
+{
+5,                 // distribution -999 _-^_^-_ +999
+-999, 999,         // each weight value may be useful, especially...
+  -5, -0.3,        // ...little non-zero values
+  -3, -0.6,
+ 0.6, 3,
+ 0.3, 5,
+};
+*/
+
+#endif
+
