|
@@ -1,7 +1,53 @@
|
|
|
#include "OptimizerBase.h"
|
|
|
#include <iostream>
|
|
|
+#include <filesystem>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
|
|
|
namespace mdd{
|
|
|
+ bool OptimizerBase::Permutation::operator== (const Permutation& ind) {
|
|
|
+ return (dna == ind.dna);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::Permutation::same(Permutation const& a, Permutation const& b) {
|
|
|
+ bool check1 = (a.dna == b.dna);
|
|
|
+ bool check2 = true;
|
|
|
+ if (a.dna.size() != b.dna.size())
|
|
|
+ {
|
|
|
+ check2 = false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ for (size_t i = 0; i < a.dna.size(); i++)
|
|
|
+ {
|
|
|
+ if (a.dna[i].size() != b.dna[i].size())
|
|
|
+ {
|
|
|
+ check2 = false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for (size_t j = 0; j < a.dna[i].size(); j++)
|
|
|
+ {
|
|
|
+ if (a.dna[i][j] != b.dna[i][j])
|
|
|
+ {
|
|
|
+ check2 = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (check1 != check2)
|
|
|
+ {
|
|
|
+ int test = 0;
|
|
|
+ }
|
|
|
+ return check1;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::Permutation::smaller(Permutation const& a, Permutation const& b) {
|
|
|
+ return (a.dna < b.dna);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
bool OptimizerBase::connect(std::shared_ptr<IModule> module) {
|
|
|
_module = module;
|
|
|
return true;
|
|
@@ -99,14 +145,20 @@ namespace mdd{
|
|
|
std::string key = (*jstate_it)["value"].get<std::string>();
|
|
|
if (key == "run")
|
|
|
{
|
|
|
+ if (_base_config["optimizer"]["state"]["value"] == "stop")
|
|
|
+ {
|
|
|
+ reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ _base_config["optimizer"]["state"]["value"] = "run";
|
|
|
updateLayout();
|
|
|
_thread_ptr = std::make_shared<std::thread>(&OptimizerBase::update,this);
|
|
|
}
|
|
|
else if (key == "pause") {
|
|
|
-
|
|
|
+ _base_config["optimizer"]["state"]["value"] = "pause";
|
|
|
}
|
|
|
else {//stop
|
|
|
-
|
|
|
+ _base_config["optimizer"]["state"]["value"] = "stop";
|
|
|
}
|
|
|
}
|
|
|
jstate_it = jit->find("evaluate");
|
|
@@ -135,12 +187,27 @@ namespace mdd{
|
|
|
//virtual std::string getGeneratorID() = 0;
|
|
|
void OptimizerBase::load(const json& j) {
|
|
|
configure(j);
|
|
|
+ auto it = j.find("db");
|
|
|
+ if (it != j.end())
|
|
|
+ {
|
|
|
+ createDB(it->get<std::string>());
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ createDB("C:/Users/Willi/Documents/projects/mdd/lib/test/db/optimization.db");
|
|
|
+ }
|
|
|
+
|
|
|
+ loadDB(j);
|
|
|
}
|
|
|
json OptimizerBase::dump() {
|
|
|
json ret = _base_config;
|
|
|
ret["ID"] = getIdentifier();
|
|
|
ret["type"] = type;
|
|
|
ret["key"] = key;
|
|
|
+
|
|
|
+ ret["db"] = "C:/Users/Willi/Documents/projects/mdd/lib/test/db/optimization.db";
|
|
|
+
|
|
|
+ ret["permutations"] = dumpPermutations();
|
|
|
+ ret["steps"] = dumpSteps();
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -162,13 +229,15 @@ namespace mdd{
|
|
|
void OptimizerBase::callback_add_step(const std::vector<Permutation>& pers){
|
|
|
json ret;
|
|
|
ret["step"] = step;
|
|
|
- for (auto& ind : pers)
|
|
|
+ _mutex.lock();
|
|
|
+ for (int i = 0; i < pers.size(); ++i)
|
|
|
{
|
|
|
- json jind;
|
|
|
- jind["fitness"] = ind.fitness;
|
|
|
- jind["dna"] = ind.dna;
|
|
|
- ret["permutations"].push_back(jind);
|
|
|
+ auto ind = pers[i];
|
|
|
+ addPermutation(ind);
|
|
|
+ addStep(step, ind.dna);
|
|
|
+ ret["permutations"].push_back(Permutation_to_JSON(ind));
|
|
|
}
|
|
|
+ _mutex.unlock();
|
|
|
json jcall;
|
|
|
jcall["operation"] = "add";
|
|
|
jcall["args"]["subject"] = getIdentifier();
|
|
@@ -176,20 +245,12 @@ namespace mdd{
|
|
|
_callback(jcall);
|
|
|
}
|
|
|
|
|
|
- void OptimizerBase::callback_evaluate_opt(const OptimizerBase::opt_state& state, const Permutation& per) {
|
|
|
+ void OptimizerBase::callback_evaluate_opt(const Permutation& per) {
|
|
|
json ret;
|
|
|
ret["step"] = step;
|
|
|
- json jind;
|
|
|
- jind["fitness"] = state.opt_value;
|
|
|
- jind["dna"] = per.dna;
|
|
|
- if (state.module_state == state::STATE_ERROR)
|
|
|
- {
|
|
|
- jind["status"] = "error";
|
|
|
- }
|
|
|
- else {
|
|
|
- jind["status"] = "ok";
|
|
|
- }
|
|
|
- jind["processor"] = _module->dump();
|
|
|
+ changePermutation(per);
|
|
|
+ json jind = Permutation_to_JSON(per);
|
|
|
+ //jind["processor"] = _module->dump();
|
|
|
ret["permutation"] = jind;
|
|
|
json jcall;
|
|
|
jcall["operation"] = "change";
|
|
@@ -198,10 +259,356 @@ namespace mdd{
|
|
|
_callback(jcall);
|
|
|
}
|
|
|
|
|
|
+ void OptimizerBase::callback_reset() {
|
|
|
+ json ret;
|
|
|
+ ret["step"] = step;
|
|
|
+
|
|
|
+ json jcall;
|
|
|
+ jcall["operation"] = "reset";
|
|
|
+ jcall["args"]["subject"] = getIdentifier();
|
|
|
+ jcall["args"]["object"] = ret;
|
|
|
+ _callback(jcall);
|
|
|
+ }
|
|
|
+
|
|
|
+ void OptimizerBase::reset(){
|
|
|
+ step = -1;
|
|
|
+ callback_reset();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::reachAbort(const std::vector<Permutation>& pers) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
OptimizerBase::~OptimizerBase() {
|
|
|
if (_thread_ptr != nullptr)
|
|
|
{
|
|
|
_thread_ptr->join();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ int sql_callback(void* data, int argc, char** argv, char** azColName) {
|
|
|
+ static_cast<OptimizerBase*>(data)->sql_callback(argc, argv, azColName);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::exec_sql(const std::string& sql) {
|
|
|
+ char* zErrMsg = 0;
|
|
|
+ int rc;
|
|
|
+ sqlite3* _db;
|
|
|
+
|
|
|
+ // Open database
|
|
|
+ //if (std::filesystem::exists(_db_path)) {
|
|
|
+ // sqlite3_open(_db_path.c_str(), &_db);
|
|
|
+ // return true;
|
|
|
+ //}
|
|
|
+ rc = sqlite3_open(_db_path.c_str(), &_db);
|
|
|
+
|
|
|
+ if (rc) {
|
|
|
+ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(_db));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //fprintf(stdout, "Opened database successfully\n");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // Execute SQL statement
|
|
|
+ rc = sqlite3_exec(_db, sql.c_str(), mdd::sql_callback, this, &zErrMsg);
|
|
|
+
|
|
|
+ if (rc != SQLITE_OK) {
|
|
|
+ fprintf(stderr, "SQL error: %s\n", zErrMsg);
|
|
|
+ sqlite3_free(zErrMsg);
|
|
|
+ sqlite3_close(_db);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlite3_close(_db);
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ json OptimizerBase::exec_sql_with_callback(const std::string& sql) {
|
|
|
+ char* zErrMsg = 0;
|
|
|
+ int rc;
|
|
|
+ sqlite3* _db;
|
|
|
+ _jcall = json::basic_json();
|
|
|
+
|
|
|
+ // Open database
|
|
|
+ rc = sqlite3_open(_db_path.c_str(), &_db);
|
|
|
+
|
|
|
+ if (rc) {
|
|
|
+ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(_db));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ //fprintf(stdout, "Opened database successfully\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ // Execute SQL statement
|
|
|
+ rc = sqlite3_exec(_db, sql.c_str(), mdd::sql_callback, this, &zErrMsg);
|
|
|
+
|
|
|
+ if (rc != SQLITE_OK) {
|
|
|
+ fprintf(stderr, "SQL error: %s\n", zErrMsg);
|
|
|
+ sqlite3_free(zErrMsg);
|
|
|
+ sqlite3_close(_db);
|
|
|
+ return json::basic_json();
|
|
|
+ }
|
|
|
+ sqlite3_close(_db);
|
|
|
+
|
|
|
+ return _jcall;
|
|
|
+ }
|
|
|
+
|
|
|
+ int OptimizerBase::sql_callback(int argc, char** argv, char** azColName) {
|
|
|
+ json jelem;
|
|
|
+ for (size_t i = 0; i < argc; i++)
|
|
|
+ {
|
|
|
+ jelem[azColName[i]] = std::string((argv[i] ? argv[i] : "NULL"));
|
|
|
+ }
|
|
|
+ _jcall.push_back(jelem);
|
|
|
+ //printf(jelem.dump().c_str());
|
|
|
+ ///TODO test
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ json OptimizerBase::Permutation_to_JSON(const Permutation& per) {
|
|
|
+ json ret;
|
|
|
+ ret["dna"] = per.dna;
|
|
|
+ ret["fitness"] = per.fitness;
|
|
|
+ ret["status"] = per.status;
|
|
|
+ ret["time"] = per.time;
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ OptimizerBase::Permutation OptimizerBase::JSON_to_Permutation(const json& j) {
|
|
|
+ Permutation per;
|
|
|
+ json jelem;
|
|
|
+ if (j.is_array())
|
|
|
+ {
|
|
|
+ jelem = *j.begin();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ jelem = j;
|
|
|
+ }
|
|
|
+ auto ittest = jelem.find("dna");
|
|
|
+ if (ittest == jelem.end())
|
|
|
+ {
|
|
|
+ int test = 0;
|
|
|
+ }
|
|
|
+ json jval = json::parse(jelem["dna"].get<std::string>());
|
|
|
+ per.dna = jval.get<std::vector<std::vector<double>>>();
|
|
|
+
|
|
|
+ jval = json::parse(jelem["fitness"].get<std::string>());
|
|
|
+ per.fitness = jval.get<double>();
|
|
|
+ auto 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())
|
|
|
+ {
|
|
|
+ jval = json::parse(it->get<std::string>());
|
|
|
+ per.time = jval.get<double>();
|
|
|
+ }
|
|
|
+
|
|
|
+ return per;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::createDB(const std::string& db_path) {
|
|
|
+ _db_path = db_path;
|
|
|
+ if (std::filesystem::exists(_db_path)) {
|
|
|
+ //return clearDB(db_path);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ sqlite3* _db;
|
|
|
+ int rc;
|
|
|
+ char* sql;
|
|
|
+
|
|
|
+ bool ret;
|
|
|
+
|
|
|
+ // Create SQL statement
|
|
|
+ sql = "CREATE TABLE PERMUTATIONS(" \
|
|
|
+ "dna TEXT NOT NULL PRIMARY KEY," \
|
|
|
+ "fitness FLOAT," \
|
|
|
+ "time FLOAT," \
|
|
|
+ "status TEXT" \
|
|
|
+ ");";
|
|
|
+
|
|
|
+ ret = exec_sql(sql);
|
|
|
+
|
|
|
+ // Create SQL statement
|
|
|
+ sql = "CREATE TABLE STEPS(" \
|
|
|
+ "step INTEGER NOT NULL," \
|
|
|
+ "dna TEXT NOT NULL," \
|
|
|
+ "CONSTRAINT PK_PERMUTATIONS PRIMARY KEY (step, dna)"
|
|
|
+ ");";
|
|
|
+
|
|
|
+ ret = ret && exec_sql(sql);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::clearDB() {
|
|
|
+
|
|
|
+ std::string sql;
|
|
|
+ sql = "DELETE FROM PERMUTATIONS;";
|
|
|
+ exec_sql(sql);
|
|
|
+ sql = "DELETE FROM STEPS;";
|
|
|
+ return exec_sql(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::loadDB(const json& j) {
|
|
|
+ bool ret = true;
|
|
|
+ bool found = false;
|
|
|
+ clearDB();
|
|
|
+ auto it = j.find("permutations");
|
|
|
+ if (it != j.end())
|
|
|
+ {
|
|
|
+ found = true;
|
|
|
+ ret = ret && loadPermutationDB(*it);
|
|
|
+ }
|
|
|
+
|
|
|
+ it = j.find("steps");
|
|
|
+ if (it != j.end())
|
|
|
+ {
|
|
|
+ found = found && true;
|
|
|
+ ret = ret && loadStepDB(*it);
|
|
|
+ }
|
|
|
+ step = -1;
|
|
|
+ if (found)
|
|
|
+ {
|
|
|
+ std::vector<Permutation> bests;
|
|
|
+ do
|
|
|
+ {
|
|
|
+ ++step;
|
|
|
+ bests = findBest(step);
|
|
|
+ if (bests.empty())
|
|
|
+ {
|
|
|
+ --step;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (!reachAbort(bests));
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret && found;
|
|
|
+ }
|
|
|
+ bool OptimizerBase::loadStepDB(const json& j) {
|
|
|
+ bool ret = true;
|
|
|
+ for (size_t i = 0; i < j.size(); i++)
|
|
|
+ {
|
|
|
+ json jstep = j.at(i);
|
|
|
+ ret = ret && addStep(json::parse(jstep["step"].get<std::string>()).get<int>(), json::parse(jstep["dna"].get<std::string>()));
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::loadPermutationDB(const json& j){
|
|
|
+ bool ret = true;
|
|
|
+ for (size_t i = 0; i < j.size(); i++)
|
|
|
+ {
|
|
|
+ ret = ret && addPermutation(JSON_to_Permutation(j.at(i)));
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ json OptimizerBase::dumpPermutations() {
|
|
|
+ std::string sql = "SELECT * FROM PERMUTATIONS;";
|
|
|
+ json ret = exec_sql_with_callback(sql);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ json OptimizerBase::dumpSteps() {
|
|
|
+ std::string sql = "SELECT * FROM STEPS;";
|
|
|
+ json ret = exec_sql_with_callback(sql);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::addPermutation(const Permutation& per) {
|
|
|
+ // Create SQL statement
|
|
|
+ json jdna;
|
|
|
+ jdna = per.dna;
|
|
|
+ std::string sval = "'" + jdna.dump() + "', " + std::to_string(per.fitness)+ ", " + std::to_string(per.time) + ", " + std::to_string((char)(per.status));
|
|
|
+ std::string sql;
|
|
|
+ sql = "INSERT INTO PERMUTATIONS (dna, fitness, time, status) "\
|
|
|
+ "VALUES (" + sval + "); ";
|
|
|
+
|
|
|
+ return exec_sql(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::addStep(int step, json dna) {
|
|
|
+ std::string sql = "INSERT INTO STEPS (step, dna) "\
|
|
|
+ "VALUES (" + std::to_string(step) + ", '" + dna.dump() + "');";
|
|
|
+
|
|
|
+ return exec_sql(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OptimizerBase::changePermutation(const Permutation& per) {
|
|
|
+ json jdna;
|
|
|
+ jdna = per.dna;
|
|
|
+ std::string sql;
|
|
|
+ sql = "UPDATE PERMUTATIONS "\
|
|
|
+ "SET fitness = "+ std::to_string(per.fitness)+ ", time = "+ std::to_string(per.time) + ", status = " + std::to_string((char)(per.status)) + " "\
|
|
|
+ "WHERE dna = '" + jdna.dump() + "';";
|
|
|
+
|
|
|
+ return exec_sql(sql);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::shared_ptr<OptimizerBase::Permutation> OptimizerBase::findPermutation(std::vector<std::vector<double>> dna) {
|
|
|
+ json jdna;
|
|
|
+ jdna = dna;
|
|
|
+ std::string sql = "SELECT * FROM PERMUTATIONS "\
|
|
|
+ "WHERE dna = '" + jdna.dump() + "' AND status = " + std::to_string((char)(state::CHANGED)) + "; ";
|
|
|
+ json ret;
|
|
|
+ ret = exec_sql_with_callback(sql);
|
|
|
+ if (ret != nullptr)
|
|
|
+ {
|
|
|
+ return std::make_shared<Permutation>(JSON_to_Permutation(ret));
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 "\
|
|
|
+ "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);
|
|
|
+ if (ret != nullptr)
|
|
|
+ {
|
|
|
+ return std::make_shared<Permutation>(JSON_to_Permutation(ret));
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ json OptimizerBase::getPermutations() {
|
|
|
+ std::string sql;
|
|
|
+ sql = "SELECT s.step, p.dna, p.fitness, p.time, p.status FROM PERMUTATIONS AS p "\
|
|
|
+ "LEFT JOIN STEPS AS s ON s.dna = p.dna; ";
|
|
|
+ json ret = exec_sql_with_callback(sql);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<OptimizerBase::Permutation> OptimizerBase::findBest(int step) {
|
|
|
+ std::string sql = "SELECT * FROM PERMUTATIONS "\
|
|
|
+ "WHERE dna = ("\
|
|
|
+ "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 "\
|
|
|
+ "LEFT JOIN STEPS AS s ON s.dna = p.dna "\
|
|
|
+ "WHERE s.step = " + std::to_string(step)+"));";
|
|
|
+ json ret = exec_sql_with_callback(sql);
|
|
|
+ std::vector<Permutation> vec;
|
|
|
+ if (ret.is_array())
|
|
|
+ {
|
|
|
+ for (size_t i = 0; i < ret.size(); i++)
|
|
|
+ {
|
|
|
+ vec.push_back(JSON_to_Permutation(ret[i]));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return vec;
|
|
|
+ }
|
|
|
}
|