Index: cpp/frams/genetics/fL/fL_matheval.cpp
===================================================================
--- cpp/frams/genetics/fL/fL_matheval.cpp	(revision 780)
+++ cpp/frams/genetics/fL/fL_matheval.cpp	(revision 797)
@@ -1,6 +1,11 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2018  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
 #include <frams/util/extvalue.h>
 #include <frams/util/sstring.h>
 #include <stack>
 #include "fL_matheval.h"
+#include <frams/genetics/genooperators.h>
 
 // Used available operators in MathEvaluation
@@ -94,18 +99,26 @@
 }
 
+void MathEvaluation::registerOperator(double(*operation)(double left, double right), int precedence, MathEvaluation::Associativity assoc, std::string opsymbol)
+{
+	operators[opsymbol] = new Operator(operation, precedence, assoc, opsymbol);
+	operatorstrings.push_back(opsymbol);
+}
+
 void MathEvaluation::registerOperators()
 {
 	// list of available operators in MathEvaluation
-	operators["+"] = new Operator(madd, 2, Associativity::LEFT, "+");
-	operators["-"] = new Operator(msub, 2, Associativity::LEFT, "-");
-	operators["*"] = new Operator(mmul, 3, Associativity::LEFT, "*");
-	operators["&"] = new Operator(mand, 0, Associativity::LEFT, "&");
-	operators["|"] = new Operator(mor, 0, Associativity::LEFT, "|");
-	operators[">"] = new Operator(mgreater, 1, Associativity::LEFT, ">");
-	operators["<"] = new Operator(mless, 1, Associativity::LEFT, "<");
-	operators[">="] = new Operator(meqgreater, 1, Associativity::LEFT, ">=");
-	operators["<="] = new Operator(meqless, 1, Associativity::LEFT, "<=");
-	operators["="] = new Operator(mequal, 1, Associativity::RIGHT, "=");
-	operators["~"] = new Operator(mnotequal, 1, Associativity::RIGHT, "~");
+	registerOperator(madd, 2, Associativity::LEFT, "+");
+	registerOperator(msub, 2, Associativity::LEFT, "-");
+	registerOperator(mmul, 3, Associativity::LEFT, "*");
+	registerOperator(mgreater, 1, Associativity::LEFT, ">");
+	registerOperator(mless, 1, Associativity::LEFT, "<");
+	registerOperator(meqgreater, 1, Associativity::LEFT, ">=");
+	registerOperator(meqless, 1, Associativity::LEFT, "<=");
+	registerOperator(mequal, 1, Associativity::RIGHT, "=");
+	registerOperator(mnotequal, 1, Associativity::RIGHT, "~");
+	registerOperator(mand, 0, Associativity::LEFT, "&");
+	registerOperator(mor, 0, Associativity::LEFT, "|");
+	arithmeticoperatorscount = 3;
+	comparisonoperatorscount = 6;
 }
 
@@ -159,4 +172,5 @@
 int MathEvaluation::convertString(std::string expression)
 {
+	originalexpression = expression;
 	clearPostfix(); //clear previous objects
 	ExtValue val;
@@ -193,6 +207,6 @@
 					{
 						delete operatorstack.back();
-						operatorstack.pop_back();
-					}
+					}
+					operatorstack.pop_back();
 				}
 				return -1;
@@ -247,6 +261,6 @@
 					{
 						delete operatorstack.back();
-						operatorstack.pop_back();
-					}
+					}
+					operatorstack.pop_back();
 				}
 				return -1;
@@ -407,6 +421,6 @@
 					{
 						delete operatorstack.back();
-						operatorstack.pop_back();
-					}
+					}
+					operatorstack.pop_back();
 				}
 				return -1;
@@ -434,6 +448,6 @@
 				{
 					delete operatorstack.back();
-					operatorstack.pop_back();
-				}
+				}
+				operatorstack.pop_back();
 			}
 			return -1;
@@ -448,5 +462,4 @@
 	// stack holds number used during operator execution
 	std::stack<Number *> numberstack;
-
 	for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
 	{
@@ -532,4 +545,9 @@
 int MathEvaluation::RPNToInfix(std::string &result)
 {
+	if (postfixlist.size() == 0)
+	{
+		result = "";
+		return 0;
+	}
 	// stack holds stringified chunk and its precedence
 	std::stack<std::pair<std::string, int>> chunks;
@@ -585,5 +603,5 @@
 	{
 		logMessage("MathEvaluation", "RPNToInfix", LOG_ERROR,
-			"Could not convert RPN notation to infix notation");
+			"Could not convert RPN notation to infix notation - formula is not complete");
 		return -1;
 	}
@@ -592,2 +610,199 @@
 	return 0;
 }
+
+void MathEvaluation::mutateValueOrVariable(MathEvaluation::Number *&currval, bool usetime)
+{
+	if (randomN(2) == 0 && varcount > 0) // use variable
+	{
+		if (currval && currval->type == TokenType::NUMBER)
+		{
+			delete currval;
+		}
+		int var = randomN(varcount + (usetime ? 1 : 0));
+		if (varcount == var) // time is used
+		{
+			currval = t;
+		}
+		else
+		{
+			currval = vars[var];
+		}
+	}
+	else
+	{
+		if (!currval || currval->type == TokenType::VARIABLE)
+		{
+			currval = new Number(rnd01);
+		}
+		else
+		{
+			currval->value = rnd01;
+		}
+	}
+}
+
+MathEvaluation::Operator* MathEvaluation::getRandomOperator(int type)
+{ // 0 for all, 1 for arithmetic only, 2 for logical only
+	int randop = type == 2 ? arithmeticoperatorscount : 0;
+	int count = arithmeticoperatorscount;
+	if (type == 0)
+	{
+		count = operatorstrings.size();
+	}
+	else if (type == 2)
+	{
+		count = operatorstrings.size() - arithmeticoperatorscount;
+	}
+	randop += randomN(count);
+	return operators[operatorstrings[randop]];
+}
+
+void MathEvaluation::mutateConditional()
+{
+	if (varcount > 0)
+	{
+		int currsize = postfixlist.size();
+		int varid = randomN(varcount);
+		postfixlist.push_back(vars[varid]);
+		if (randomN(2) == 0 && varcount > 1)
+		{
+			int varid2 = randomN(varcount - 1);
+			if (varid2 >= varid) varid2++;
+			postfixlist.push_back(vars[varid2]);
+		}
+		else
+		{
+			Number *num = new Number(rnd01);
+			postfixlist.push_back(num);
+		}
+		int opid = arithmeticoperatorscount + randomN(comparisonoperatorscount);
+		postfixlist.push_back(operators[operatorstrings[opid]]);
+		if (currsize > 0)
+		{
+			postfixlist.push_back(operators["&"]);
+		}
+	}
+}
+
+int MathEvaluation::mutate(bool logical, bool usetime)
+{
+	if (postfixlist.size() == 0)
+	{
+		Number *val = new Number(rnd01);
+		postfixlist.push_back(val);
+		return -1;
+	}
+	int method = randomN(postfixlist.size() < MAX_MUT_FORMULA_SIZE ? MATH_MUT_COUNT : MATH_MUT_COUNT - 1);
+	switch (method)
+	{
+	case MATH_MUT_INSERTION:
+	{
+		std::list<Token *> insertpair;
+		Number *val = NULL;
+		mutateValueOrVariable(val, usetime);
+		insertpair.push_back(val);
+		std::list<Token *>::iterator it = postfixlist.begin();
+		// insertion can be applied from 1st occurrence
+		int insertlocation = 1 + randomN(postfixlist.size() - 1);
+		std::advance(it, insertlocation);
+		Operator *rndop;
+		if (insertlocation == (int)postfixlist.size() - 1)
+		{
+			rndop = getRandomOperator(logical ? 2 : 1);
+		}
+		else
+		{
+			rndop = getRandomOperator(logical ? 0 : 1);
+
+		}
+		insertpair.push_back(rndop);
+		postfixlist.insert(it, insertpair.begin(), insertpair.end());
+		break;
+	}
+	case MATH_MUT_CHANGEVAL:
+	{
+		std::vector<std::list<Token *>::iterator> numbersineval;
+		int id = 0;
+		for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
+		{
+			if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
+			{
+				numbersineval.push_back(it);
+			}
+			id++;
+		}
+		int randid = randomN(numbersineval.size());
+		Number *numptr = (Number *)(*numbersineval[randid]);
+		mutateValueOrVariable(numptr, usetime);
+		(*numbersineval[randid]) = numptr;
+		break;
+	}
+	case MATH_MUT_CHANGEOPER:
+	{
+		std::vector<std::list<Token *>::iterator> ops;
+		for (std::list<Token *>::iterator it = postfixlist.begin(); it != postfixlist.end(); it++)
+		{
+			if ((*it)->type == TokenType::OPERATOR)
+			{
+				ops.push_back(it);
+			}
+		}
+		if (ops.size() > 0)
+		{
+			int randid = randomN(ops.size());
+			Operator *rndop;
+			if (randid == (int)ops.size() - 1)
+			{
+				rndop = getRandomOperator(logical ? 2 : 1);
+			}
+			else
+			{
+				rndop = getRandomOperator(logical ? 0 : 1);
+			}
+			(*ops[randid]) = rndop;
+		}
+		break;
+	}
+	case MATH_MUT_DELETION:
+	{
+		std::list<Token *>::iterator it = postfixlist.begin();
+		std::vector<std::list<Token *>::iterator> firstofpairs;
+		while (it != postfixlist.end())
+		{
+			if ((*it)->type == TokenType::NUMBER || (*it)->type == TokenType::VARIABLE)
+			{
+				std::list<Token *>::iterator next = it;
+				next++;
+				if (next != postfixlist.end() && (*next)->type == TokenType::OPERATOR)
+				{
+					firstofpairs.push_back(it);
+				}
+			}
+			it++;
+		}
+		if (firstofpairs.size() > 0)
+		{
+			int rndid = randomN(firstofpairs.size());
+			if ((*firstofpairs[rndid])->type == TokenType::NUMBER)
+			{
+				delete (*firstofpairs[rndid]);
+			}
+			firstofpairs[rndid] = postfixlist.erase(firstofpairs[rndid]);
+			postfixlist.erase(firstofpairs[rndid]);
+		}
+		break;
+	}
+	}
+	return method;
+}
+
+std::string MathEvaluation::getStringifiedRPN()
+{
+	std::string res = "";
+	for (Token *el: postfixlist)
+	{
+		res += el->toString();
+		res += " ";
+	}
+	return res;
+}
