Explorar o código

hard restriction is implemented

Willi Zschiebsch %!s(int64=4) %!d(string=hai) anos
pai
achega
83e4b47d93

+ 2 - 3
lib/include/IOptimizer.h

@@ -1,5 +1,4 @@
-#ifndef IOPTIMIZER_H
-#define IOPTIMIZER_H
+#pragma once
 #include "json.hpp"
 #include <IModule.h>
 #include "IManager.h"
@@ -14,9 +13,9 @@ namespace mdd {
 			virtual bool connect(std::shared_ptr<IModule> module) = 0;
 			
 			virtual bool setEvaluation(std::string func) = 0;
+			virtual bool setRestriction(std::string func) = 0;
 			virtual double update() = 0;
 			virtual void attachCallback(std::function<json(const json&)> callback) = 0;
 			virtual json getPermutations() = 0;
 	};
 }
-#endif // !IOPTIMIZER_H

+ 8 - 2
lib/include/OptimizerBase.h

@@ -24,18 +24,21 @@ namespace mdd {
 		std::vector<std::shared_ptr<IOutput>> _outputs;
 		std::vector<double> _output_vals;
 		exprtk::expression<double> _func_expr;
+		exprtk::expression<double> _func_restirct_expr;
 
 		std::function<json(const json&)> _callback;
 
 		std::shared_ptr<std::thread> _thread_ptr;
 
 		int step = -1;
+		int _precision = 3;
 
 		struct opt_state {
 			state module_state = state::STATE_ERROR;
 			double opt_value = 0;
+			bool fullfill_restriction = false;
 		};
-		opt_state updateOutputs();
+		OptimizerBase::opt_state updateOutputs();
 		OptimizerBase(const std::string& base_config = "{}");
 
 		bool configureChild(const json& config) override;
@@ -44,6 +47,7 @@ namespace mdd {
 		public:
 			std::vector<std::vector<double>> dna;
 			double fitness = 0;
+			bool accepted = false;
 			double time = 0;
 			state status = state::UNCHANGED;
 
@@ -55,6 +59,7 @@ namespace mdd {
 		bool connect(std::shared_ptr<IModule> module) override;
 		void updateLayout();
 		bool setEvaluation(std::string func) override;
+		bool setRestriction(std::string func) override;
 
 		bool configure(const json& config) override;
 		const json& getConfiguration() override;
@@ -66,7 +71,7 @@ namespace mdd {
 		void attachCallback(std::function<json(const json&)> callback) override;
 		//state update() override;
 		void callback_add_step(const std::vector<Permutation>& pers);
-		void callback_evaluate_opt(const Permutation& per);
+		void callback_evaluate_opt(const Permutation& per, bool sql = false);
 		void callback_autosave();
 		void callback_reset();
 		~OptimizerBase();
@@ -102,6 +107,7 @@ namespace mdd {
 
 	public:
 		std::shared_ptr<Permutation> findPermutation(std::vector<std::vector<double>> dna);
+		json findPermutationJSON(std::vector<std::vector<double>> dna);
 		std::shared_ptr<Permutation> getPermutation(int step, std::vector<std::vector<double>> dna);
 		json getPermutations() override;
 		std::vector<Permutation> findBest(int step);

+ 1 - 2
lib/include/OptimizerEvolutionary.h

@@ -21,10 +21,9 @@ namespace mdd {
 		Permutation _old_best;
 
 		int _min_generations;
-		double _max_fitness;
 		size_t _grow_generation;
 		size_t _converges;
-		double _precision;
+		
 
 		void evolve();
 		void evaluate(size_t ignore_len = 0);

+ 104 - 16
lib/src/OptimizerBase.cpp

@@ -65,6 +65,7 @@ namespace mdd{
 				//std::cout << "get: " << i << ": " << _output_vals[i] << std::endl;
 			}
 			ret.opt_value = _func_expr.value();
+			ret.fullfill_restriction = (bool)_func_restirct_expr.value();
 			//std::cout << "get: " << "opt" << ": " << ret.opt_value << std::endl;
 		}
 
@@ -90,9 +91,13 @@ namespace mdd{
 		json jevalue;
 		jevalue["value"] = "";
 
+		json jrestrict;
+		jrestrict["value"] = "true";
+
 		json jsub;
 		jsub["state"] = jstate;
 		jsub["evaluate"] = jevalue;
+		jsub["restriction"] = jrestrict;
 		_base_config["optimizer"] = jsub;
 	}
 
@@ -133,6 +138,22 @@ namespace mdd{
 		exprtk::parser<double> parser;
 		return parser.compile(func, _func_expr);
 	}
+
+	bool OptimizerBase::setRestriction(std::string func)
+	{
+		updateLayout();
+		exprtk::symbol_table<double> symbol_table;
+		for (size_t i = 0; i < _output_vals.size(); ++i)
+		{
+			symbol_table.add_variable("out" + std::to_string(i), _output_vals[i]);
+		}
+		symbol_table.add_constants();
+
+		_func_restirct_expr.register_symbol_table(symbol_table);
+
+		exprtk::parser<double> parser;
+		return parser.compile(func, _func_restirct_expr);
+	}
 	
 	bool OptimizerBase::configure(const json& config) {
 		json jconfig = config;
@@ -168,6 +189,12 @@ namespace mdd{
 				_base_config["optimizer"]["evaluate"]["value"] = (*jstate_it)["value"].get<std::string>();
 			}
 
+			jstate_it = jit->find("restriction");
+			if (jstate_it != jit->end()) {
+				updateLayout();
+				setRestriction((*jstate_it)["value"].get<std::string>());
+				_base_config["optimizer"]["restriction"]["value"] = (*jstate_it)["value"].get<std::string>();
+			}
 		}
 		jit = jconfig.find("configure");
 		if (jit != jconfig.end())
@@ -245,13 +272,32 @@ namespace mdd{
 		_callback(jcall);
 	}
 
-	void OptimizerBase::callback_evaluate_opt(const Permutation& per) {
+	void OptimizerBase::callback_evaluate_opt(const Permutation& per, bool sql) {
 		json ret;
 		ret["step"] = step;
-		
-		json jind = Permutation_to_JSON(per);
-		jind["processor"] = _module->dump();
-		changePermutation(jind);
+		json jind;
+		if (sql)
+		{
+			jind = Permutation_to_JSON(per);
+			jind["processor"] = _module->dump();
+			std::vector< std::vector<double>> outs;
+			for (size_t i = 0; i < _output_vals.size(); ++i)
+			{
+				outs.push_back(_outputs[i]->getValue());
+				//std::cout << "get: " << i << ": " << _output_vals[i] << std::endl;
+				if (_outputs[i]->getValue()[0] != per.fitness)
+				{
+					int test = 0;
+				}
+			}
+			jind["outputs"] = outs;
+			changePermutation(jind);
+		}
+		else
+		{
+			jind = findPermutationJSON(per.dna);
+		}
+
 		ret["permutation"] = jind;
 		json jcall;
 		jcall["operation"] = "change";
@@ -384,6 +430,7 @@ namespace mdd{
 		json ret;
 		ret["dna"] = per.dna;
 		ret["fitness"] = per.fitness;
+		ret["accepted"] = per.accepted;
 		ret["status"] = per.status;
 		ret["time"] = per.time;
 		return ret;
@@ -409,12 +456,21 @@ namespace mdd{
 
 		jval = json::parse(jelem["fitness"].get<std::string>());
 		per.fitness = jval.get<double>();
-		auto it = jelem.find("status");
+
+		auto it = jelem.find("accepted");
+		if (it != jelem.end())
+		{
+			jval = json::parse(it->get<std::string>());
+			per.accepted = jval.get<bool>();
+		}
+
+		it = jelem.find("status");
 		if (it != jelem.end())
 		{
 			jval = json::parse(it->get<std::string>());
 			per.status = jval.get<state>();
 		}
+
 		it = jelem.find("time");
 		if (it != jelem.end())
 		{
@@ -440,6 +496,8 @@ namespace mdd{
 		sql = "CREATE TABLE PERMUTATIONS("  \
 			"dna		TEXT	NOT NULL	PRIMARY KEY," \
 			"fitness	FLOAT," \
+			"accepted	TEXT," \
+			"outputs	TEXT," \
 			"time		FLOAT," \
 			"status		TEXT," \
 			"processor	TEXT" \
@@ -545,7 +603,8 @@ namespace mdd{
 		else {
 			sval += jper["dna"].dump();
 		}
-		sval += "', " + jper["fitness"].dump() + ", " + jper["time"].dump() + ", " + jper["status"].dump();
+		sval += "', " + jper["fitness"].dump() + ", " + jper["accepted"].dump();
+		sval += ", " + jper["time"].dump() + ", " + jper["status"].dump();
 		auto it = jper.find("processor");
 		if (it != jper.end())
 		{
@@ -561,9 +620,24 @@ namespace mdd{
 		{
 			sval += ", NULL";
 		}
+		it = jper.find("outputs");
+		if (it != jper.end())
+		{
+			if (it->is_string())
+			{
+				sval += ", '" + it->get<std::string>() + "'";
+			}
+			else {
+				sval += ", '" + it->dump() + "'";
+			}
+		}
+		else
+		{
+			sval += ", NULL";
+		}
 		
 		std::string sql;
-		sql =	"INSERT INTO PERMUTATIONS (dna, fitness, time, status, processor) "\
+		sql =	"INSERT INTO PERMUTATIONS (dna, fitness, accepted, time, status, processor, outputs) "\
 				"VALUES (" + sval + "); ";
 
 		return exec_sql(sql);
@@ -578,12 +652,18 @@ namespace mdd{
 
 	bool OptimizerBase::changePermutation(const json& jper) {
 		//std::to_string((char)(per.status))
-		std::string sval = "fitness = " + jper["fitness"].dump() + ", time = " + jper["time"].dump() + ", status = " + jper["status"].dump();
+		std::string sval = "fitness = " + jper["fitness"].dump() + ", accepted = '" +jper["accepted"].dump()+"'";
+		sval += ", time = " + jper["time"].dump() + ", status = " + jper["status"].dump();
 		auto it = jper.find("processor");
 		if (it != jper.end())
 		{
 			sval += ", processor = '" + it->dump() + "' ";
 		}
+		it = jper.find("outputs");
+		if (it != jper.end())
+		{
+			sval += ", outputs = '" + it->dump() + "' ";
+		}
 		std::string sql;
 		sql =	"UPDATE PERMUTATIONS "\
 				"SET " + sval + " "+ 
@@ -596,7 +676,7 @@ namespace mdd{
 		json jdna;
 		jdna = dna;
 		std::string sql =	"SELECT * FROM PERMUTATIONS "\
-							"WHERE dna = '" + jdna.dump() + "' AND status = " + std::to_string((char)(state::CHANGED)) + "; ";
+							"WHERE dna = '" + jdna.dump() + "' AND NOT time = 0 AND NOT status = " + std::to_string((char)(state::STATE_ERROR)) + "; ";
 		json ret;
 		ret = exec_sql_with_callback(sql);
 		if (ret != nullptr)
@@ -606,10 +686,18 @@ namespace mdd{
 		return ret;
 	}
 
+	json  OptimizerBase::findPermutationJSON(std::vector<std::vector<double>> dna) {
+		json jdna;
+		jdna = dna;
+		std::string sql = "SELECT * FROM PERMUTATIONS "\
+			"WHERE dna = '" + jdna.dump() + "'; ";
+		return exec_sql_with_callback(sql);
+	}
+
 	std::shared_ptr<OptimizerBase::Permutation> OptimizerBase::getPermutation(int step, std::vector<std::vector<double>> dna) {
 		json jdna;
 		jdna = dna;
-		std::string sql =	"SELECT p.dna, p.fitness, p.time, p.status FROM PERMUTATIONS AS p "\
+		std::string sql =	"SELECT * FROM PERMUTATIONS AS p "\
 							"LEFT JOIN STEPS AS s ON s.dna = p.dna "\
 							"WHERE s.step = " + std::to_string(step) + " AND s.dna = '" + jdna.dump() + "';";
 		json ret = exec_sql_with_callback(sql);
@@ -622,7 +710,7 @@ namespace mdd{
 
 	json OptimizerBase::getPermutations() {
 		std::string sql;
-		sql = "SELECT s.step, p.dna, p.fitness, p.time, p.status, p.processor FROM PERMUTATIONS AS p "\
+		sql = "SELECT s.step, p.dna, p.fitness, p.accepted, p.time, p.status, p.outputs, p.processor FROM PERMUTATIONS AS p "\
 			"LEFT JOIN STEPS AS s ON s.dna = p.dna; ";
 		json ret = exec_sql_with_callback(sql);
 
@@ -631,13 +719,13 @@ namespace mdd{
 
 	std::vector<OptimizerBase::Permutation> OptimizerBase::findBest(int step) {
 		std::string sql = "SELECT * FROM PERMUTATIONS "\
-			"WHERE dna = ("\
+			"WHERE dna IN ("\
 			"SELECT p.dna FROM PERMUTATIONS AS p "\
 			"LEFT JOIN STEPS AS s ON s.dna = p.dna "\
-			"WHERE s.step = " + std::to_string(step) +" AND ROUND(p.fitness,3) = ( "\
-			"SELECT MIN(ROUND(p.fitness,3)) FROM PERMUTATIONS AS p "\
+			"WHERE s.step = " + std::to_string(step) +" AND p.accepted = 'true'" +" AND ROUND(p.fitness," + std::to_string(_precision) + ") = ( "\
+			"SELECT MIN(ROUND(p.fitness,"+ std::to_string(_precision) +")) FROM PERMUTATIONS AS p "\
 			"LEFT JOIN STEPS AS s ON s.dna = p.dna "\
-			"WHERE s.step = " + std::to_string(step)+"));";
+			"WHERE s.step = " + std::to_string(step)+" AND p.accepted = 'true'));";
 		json ret = exec_sql_with_callback(sql);
 		std::vector<Permutation> vec;
 		if (ret.is_array())

+ 100 - 81
lib/src/OptimizerEvolutionary.cpp

@@ -55,44 +55,47 @@ namespace mdd {
 				it->time = elapsed_seconds.count();
 				it->status = opt.module_state;
 				it->fitness = opt.opt_value;
-				callback_evaluate_opt(*it);
+				it->accepted = opt.fullfill_restriction;
+				callback_evaluate_opt(*it, true);
 
 				if (opt.module_state == state::STATE_ERROR) {
 					_children.erase(it);
 				}
 			}
 			else{
+				*it = *per;
 				callback_evaluate_opt(*per);
 			}
 		}
 		//find fitest
 		double min = _children[0].fitness;
 		_bests.clear();
-		_bests.push_back(_children[0]);
-		for (size_t i = 1; i < _children.size(); i++)
-		{
-			if (round(min/_precision)*_precision > round(_children[i].fitness / _precision) * _precision) {
-				min = _children[i].fitness;
-				_bests.clear();
-				_bests.push_back(_children[i]);
-			}
-			else if(round(min / _precision) * _precision == round(_children[i].fitness / _precision) * _precision)
-			{
-				bool found = false;
-				for (size_t j = 0; j < _bests.size(); j++)
-				{
-					if (_children[i] == _bests[j])
-					{
-						found = true;
-						break;
-					}
-				}
-				if (!found)
-				{
-					_bests.push_back(_children[i]);
-				}
-			}
-		}
+		_bests = findBest(step);
+		//_bests.push_back(_children[0]);
+		//for (size_t i = 1; i < _children.size(); i++)
+		//{
+		//	if (round(min/_precision)*_precision > round(_children[i].fitness / _precision) * _precision) {
+		//		min = _children[i].fitness;
+		//		_bests.clear();
+		//		_bests.push_back(_children[i]);
+		//	}
+		//	else if(round(min / _precision) * _precision == round(_children[i].fitness / _precision) * _precision)
+		//	{
+		//		bool found = false;
+		//		for (size_t j = 0; j < _bests.size(); j++)
+		//		{
+		//			if (_children[i] == _bests[j])
+		//			{
+		//				found = true;
+		//				break;
+		//			}
+		//		}
+		//		if (!found)
+		//		{
+		//			_bests.push_back(_children[i]);
+		//		}
+		//	}
+		//}
 		_mutex.unlock();
 		callback_autosave();
 	}
@@ -108,26 +111,20 @@ namespace mdd {
 			{
             "value": 20
 			},
-            "max fitness":
-			{
-				"value": 0.0
-			},
             "min generations": 
 			{
 				"value": -1
 			},
             "precission":
 			{
-				"value": 0.001
+				"value": 3
 			}
         })JSON")
 	{
 		key = "OptimizerEvolutionary";
 		_converges = 0;
 		_grow_generation = 20;
-		_max_fitness = 0.0;
 		_min_generations = -1;
-		_precision = 0.001;
 	}
 
 	bool OptimizerEvolutionary::configureChild(const json& config) {
@@ -156,18 +153,7 @@ namespace mdd {
 			_base_config["configure"]["grow generation"]["value"] = _grow_generation;
 			found = true;
 		}
-		jit = config.find("max fitness");
-		if (jit != config.end())
-		{
-			json jval = jit.value()["value"];
-			if (jval.is_string())
-			{
-				jval = json::parse(jval.get<std::string>());
-			}
-			_max_fitness = jval.get<double>();
-			_base_config["configure"]["max fitness"]["value"] = _max_fitness;
-			found = true;
-		}
+
 		jit = config.find("min generations");
 		if (jit != config.end())
 		{
@@ -188,7 +174,7 @@ namespace mdd {
 			{
 				jval = json::parse(jval.get<std::string>());
 			}
-			_precision = jval.get<double>();
+			_precision = jval.get<int>();
 			_base_config["configure"]["precision"]["value"] = _precision;
 			found = true;
 		}
@@ -236,7 +222,7 @@ namespace mdd {
 
 	bool OptimizerEvolutionary::reachAbort(const std::vector<Permutation>& pers) {
 		bool check;
-		check = step < _min_generations || pers[0].fitness > _max_fitness;
+		check = step < _min_generations || pers.empty();
 		if (!check && _converges > 0)
 		{
 			bool found = false;
@@ -376,7 +362,7 @@ namespace mdd {
 		_mutex.lock();
 		if (_children.empty())
 		{
-			for (size_t i = 0; i < _grow_generation * 2; i++)
+			while (_children.size() < _grow_generation*2)
 			{
 				bool not_found = true;
 				Permutation per;
@@ -397,51 +383,84 @@ namespace mdd {
 			}
 		}
 		else {
-			////fittest should breed more
-			//detect lower border
-			double max = _children[0].fitness;
+
+			std::vector<Permutation> acc_children;
 			for (size_t i = 1; i < _children.size(); i++)
 			{
-				if (max < _children[i].fitness) {
-					max = _children[i].fitness;
+				if (_children[i].accepted) {
+					acc_children.push_back(_children[i]);
 				}
 			}
-			//detect lower border
-			double sum = 0;
-			for (size_t i = 0; i < _children.size(); i++)
-			{
-				sum += max - _children[i].fitness;
-			}
-			if (sum == 0)
+			if (!acc_children.empty())
 			{
-				sum = 1.0;
-			}
-			//multiply fitter parents
-			std::vector<Permutation> gen_pool = _children;
-			for (size_t i = 0; i < _children.size(); i++)
-			{
-				int additional = std::round((max - _children[i].fitness) / sum * 20);
-				//std::cout << additional << std::endl;
-				for (size_t j = 1; j < additional; j++)
+				////fittest should breed more
+				//detect lower border
+				double max = acc_children[0].fitness;
+				for (size_t i = 1; i < acc_children.size(); i++)
 				{
-					gen_pool.push_back(_children[i]);
+					if (max < acc_children[i].fitness) {
+						max = acc_children[i].fitness;
+					}
+				}
+				//detect lower border
+				double sum = 0;
+				for (size_t i = 0; i < acc_children.size(); i++)
+				{
+					sum += max - acc_children[i].fitness;
+				}
+				if (sum == 0)
+				{
+					sum = 1.0;
+				}
+
+				//multiply fitter parents
+				std::vector<Permutation> gen_pool = acc_children;
+				for (size_t i = 0; i < acc_children.size(); i++)
+				{
+					int additional = std::round((max - acc_children[i].fitness) / sum * 20);
+					//std::cout << additional << std::endl;
+					for (size_t j = 1; j < additional; j++)
+					{
+						gen_pool.push_back(acc_children[i]);
+					}
 				}
-			}
-			//fittest parents will also be new childrens
-			_children = _bests;
 
-			//breed
-			for (size_t i = 0; i < _grow_generation; i++)
+				//fittest parents will also be new childrens
+				_children = _bests;
+
+				//breed
+				for (size_t i = 0; i < acc_children.size()/2; i++)
+				{
+					bool not_found = true;
+					Permutation per;
+					int try_counter = 0;
+					while (not_found && try_counter < 20)
+					{
+						int p1 = (int)random_num(0, gen_pool.size() - 1);
+						int p2 = (int)random_num(0, gen_pool.size() - 1);
+						per = combine(gen_pool[p1], gen_pool[p2]);
+						++try_counter;
+						not_found = false;
+						for (size_t i = 0; i < _children.size(); i++)
+						{
+							if (_children[i].dna == per.dna)
+							{
+								not_found = true;
+								break;
+							}
+						}
+					}
+					_children.push_back(per);
+				}
+			}
+			//fill rest with random permutations
+			while (_children.size() < _grow_generation)
 			{
 				bool not_found = true;
 				Permutation per;
-				int try_counter = 0;
-				while (not_found && try_counter < 20)
+				while (not_found)
 				{
-					int p1 = (int)random_num(0, gen_pool.size() - 1);
-					int p2 = (int)random_num(0, gen_pool.size() - 1);
-					per = combine(gen_pool[p1], gen_pool[p2]);
-					++try_counter;
+					per = generatePermutation();
 					not_found = false;
 					for (size_t i = 0; i < _children.size(); i++)
 					{

BIN=BIN
lib/test/db/optimization.db


+ 0 - 0
lib/test/server/pytest.py


+ 2 - 2
lib/test/test_OptimizerEvolutionary.cpp

@@ -34,7 +34,7 @@ namespace TEST_OPTIMIZER_EVOLUTION {
         config[0]["value"] = 5;
         optimizer.configure(config.dump());
     
-        optimizer.setEvaluation("out0");
+        //optimizer.setEvaluation("out0", _exp);
     
         optimizer.update();
         auto res = optimizer.getBests()[0].dna;
@@ -68,7 +68,7 @@ namespace TEST_OPTIMIZER_EVOLUTION {
         config["converges"]["value"] = 5;
         optimizer.configure(config);
     
-        optimizer.setEvaluation("out0");
+        //optimizer.setEvaluation("out0");
     
         optimizer.update();
         auto res = optimizer.getBests()[0].dna;