diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aec573..7f948b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,3 +47,9 @@ if(Boost_ROOT) endif() add_subdirectory(${CMAKE_SOURCE_DIR}/src/) + +set(LIBSTRATEGY_BuildTests "Build tests of libstrategy" ON) +if(BUILD_TESTING AND LIBSTRATEGY_BuildTests) + enable_testing() + add_subdirectory(test) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3fdc1ea..6e69881 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.7) -project(z2s C CXX) +project(libstrategy C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_INCLUDE_CURRENT_DIR ON) option(LIBSTRATEGY_OnlyLibrary "Build only as library." OFF) @@ -38,6 +38,6 @@ install(TARGETS strategy RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) -install (FILES errors.h libz2s.h SimpleTree.h ZonotopStrategy.h DESTINATION include/libstrategy) +install (FILES errors.h SimpleTree.h ZonotopStrategy.h DESTINATION include/libstrategy) diff --git a/src/SimpleTree.cpp b/src/SimpleTree.cpp index 93a2684..b30ce34 100644 --- a/src/SimpleTree.cpp +++ b/src/SimpleTree.cpp @@ -71,10 +71,11 @@ SimpleTree SimpleTree::parse(std::istream& input, bool simplify, bool subsumptio tree._root->_cost = std::numeric_limits::infinity(); tree._root->_var = std::numeric_limits::max(); } - tree._actions.resize(raw["actions"].size()); for(auto it = raw["actions"].begin(); it != raw["actions"].end(); ++it) { auto id = atoi(it.key().c_str()); + if(id >= (int)tree._actions.size()) + tree._actions.resize(id+1); tree._actions[id] = it.value().get(); } @@ -123,7 +124,7 @@ SimpleTree SimpleTree::parse(std::istream& input, bool simplify, bool subsumptio if(minim != is_minimize) throw base_error("Expected all sub-regressors to have same minimization flag"); if(first_element) - if(!is_minimize) tree._root->_cost *= -1; + tree._root->_cost = (is_minimize ? 1 : -1) * std::numeric_limits::infinity(); first_element = false; // make sure all actions are mapped initially for(size_t i = 0; i < tree._actions.size(); ++i) @@ -139,7 +140,7 @@ SimpleTree SimpleTree::parse(std::istream& input, bool simplify, bool subsumptio tree._root = std::make_shared(); tree._root->_limit = -std::numeric_limits::infinity(); tree._root->_cost = std::numeric_limits::infinity(); - if(!is_minimize) tree._root->_cost *= -1; + tree._root->_cost = (is_minimize ? 1 : -1) * std::numeric_limits::infinity(); tree._root->_var = std::numeric_limits::max(); } @@ -149,14 +150,14 @@ SimpleTree SimpleTree::parse(std::istream& input, bool simplify, bool subsumptio } tree._is_minimization = minim != 0; if(subsumption) tree._root->subsumption_reduction(minim, tree); - if(simplify) + /*if(simplify) // disabled for now { nodemap_t nodemap; if(tree._root) tree._root = tree._root->simplify(true, nodemap, tree); if(tree._root) tree._root->_parent = nullptr; - } + }*/ return tree; } @@ -253,8 +254,8 @@ void SimpleTree::node_t::subsumption_reduction(bool minimization, SimpleTree& pa action_nodes(nodes, 0, parent._actions.size()-1, parent._statevars.size()); auto val = std::numeric_limits::infinity(); if(!minimization) val *= -1; - auto minval = val; - auto maxval = -val; + auto best = val; + auto worst = -val; for(auto& n : nodes) { auto mm = n->compute_min_max(); @@ -263,20 +264,20 @@ void SimpleTree::node_t::subsumption_reduction(bool minimization, SimpleTree& pa if(minimization) { val = std::min(val, mm.second); - minval = std::min(minval, mm.first); - maxval = std::max(maxval, mm.second); + best = std::min(best, mm.first); + worst = std::max(worst, mm.second); } else { val = std::max(val, mm.first); - minval = std::max(minval, mm.second); - maxval = std::min(maxval, mm.first); + best = std::max(best, mm.second); + worst = std::min(worst, mm.first); } } std::vector> bounds(parent._pointvars.size(), std::make_pair(-std::numeric_limits::infinity(), std::numeric_limits::infinity())); for(auto& n : nodes) { - outer |= n->check_tiles(n.get(), nodes, bounds, val, minval, maxval, minimization, parent._statevars.size() + 1); + outer |= n->check_tiles(n.get(), nodes, bounds, val, best, worst, minimization, parent._statevars.size() + 1); } std::set> values; { @@ -332,7 +333,7 @@ void SimpleTree::node_t::get_ranks(std::set >& values } -bool SimpleTree::node_t::subsumes(std::vector >& bounds, std::vector >& obounds, double val, bool minimization, size_t offset, double& best, std::pair& closest) { +bool SimpleTree::node_t::subsumes(const std::vector >& bounds, std::vector >& obounds, const double val, const bool minimization, size_t offset, double& best, std::pair& closest) { if(is_leaf()) { // TODO: continue in other trees here, maybe combination is @@ -376,51 +377,48 @@ bool SimpleTree::node_t::subsumes(std::vector >& bound } } -bool SimpleTree::node_t::check_tiles(node_t* start, std::vector >& nodes, std::vector >& bounds, double val, double minval, double maxval, bool minimization, size_t offset) +bool SimpleTree::node_t::check_tiles(node_t* start, std::vector >& nodes, std::vector >& bounds, double val, + double best_val, double worst_val, bool minimization, size_t offset) { auto obounds = bounds; if(is_leaf()) { - double best = std::numeric_limits::infinity(); + double best = (minimization ? 1 : -1) * std::numeric_limits::infinity(); _cost_bounds.first = -std::numeric_limits::infinity(); _cost_bounds.second = std::numeric_limits::infinity(); - if(std::isinf(_cost)) - _cost = maxval; - if(!minimization) - best *= -1; + if(_cost == (minimization ? 1 : -1) * std::numeric_limits::infinity()) + return false; for(auto& n : nodes) { if(n.get() == start || n == nullptr) continue; if(n->subsumes(bounds, obounds, _cost, minimization, offset, best, _cost_bounds)) { - _cost = maxval; + _cost = (minimization ? 1 : -1) * std::numeric_limits::infinity(); _cost_bounds.second = std::numeric_limits::infinity(); + return true; } - assert(best >= minval); + assert(best <= best_val || minimization); // doing max + assert(best >= best_val || !minimization); // doing min } - assert(minval <= best); - if(best >= _cost) + assert(best <= best_val || minimization); // doing max + assert(best >= best_val || !minimization); // doing min + if((minimization && best >= _cost) || + (!minimization && best <= _cost)) { - assert(_cost_bounds.first == -std::numeric_limits::infinity() || _cost_bounds.first == _cost); - assert(_cost >= minval); //std::cerr << "BEST " << _cost << " MV " << minval << " BND " << _cost_bounds.first << ": " << _cost_bounds.second << std::endl; - _cost = minval; + _cost = best_val; } else { - assert(!std::isinf(_cost_bounds.first)); - if(_cost_bounds.first != _cost && _cost_bounds.second != _cost) + if(!std::isinf(_cost_bounds.first)) { - //std::cerr << "SETTING " << _cost << " TO "; - if(std::isinf(_cost_bounds.first)) - assert(false); - else if(std::isinf(_cost_bounds.second)) - _cost = maxval; - else - _cost = (_cost_bounds.first + _cost_bounds.second) / 2.0; - assert(_cost < _cost_bounds.second); - /*std::cerr << _cost << std::endl; - std::cerr << _cost_bounds.first << " : " << _cost_bounds.second << std::endl;*/ + _cost = std::nextafter(_cost_bounds.first, std::numeric_limits::infinity()); + if(!std::isinf(_cost_bounds.second) && std::ceil(_cost) < _cost_bounds.second) + _cost = std::ceil(_cost); + } + else if(!std::isinf(_cost_bounds.second)) + { + _cost = std::nextafter(_cost_bounds.second, -std::numeric_limits::infinity()); } } return false; @@ -449,17 +447,17 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vector_cost; _low = switchnode->_low; _high = switchnode->_high; - return check_tiles(start, nodes, bounds, val, minval, maxval, minimization, offset); + return check_tiles(start, nodes, bounds, val, best_val, worst_val, minimization, offset); } else { std::swap(org, bnd.second); if(_low) - res |= _low->check_tiles(start, nodes, bounds, val, minval, maxval, minimization, offset); + res |= _low->check_tiles(start, nodes, bounds, val, best_val, worst_val, minimization, offset); std::swap(org, bnd.second); std::swap(org, bnd.first); if(_high) - res |= _high->check_tiles(start, nodes, bounds, val, minval, maxval, minimization, offset); + res |= _high->check_tiles(start, nodes, bounds, val, best_val, worst_val, minimization, offset); std::swap(org, bnd.first); } _cost_bounds.first = std::max(_low->_cost_bounds.first, _high->_cost_bounds.first); @@ -474,7 +472,7 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vectormidcost(*_high, minval, maxval); + _cost = _low->midcost(*_high, best_val, worst_val); //std::cerr << "NC " << _cost << std::endl; _low = nullptr; _high = nullptr; @@ -498,7 +496,7 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vector_low; - nc = other->midcost(*_low, minval, maxval); + nc = other->midcost(*_low, best_val, worst_val); assert(!std::isnan(nc)); } else if( !_low->is_leaf() && @@ -510,7 +508,7 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vector_high; - nc = other->midcost(*_high, minval, maxval); + nc = other->midcost(*_high, best_val, worst_val); assert(!std::isnan(nc)); } @@ -522,7 +520,7 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vector_high; other->_cost = nc; // we could compute the values on the fly; but no time currently - check_tiles(start, nodes, bounds, val, minval, maxval, minimization, offset); + check_tiles(start, nodes, bounds, val, best_val, worst_val, minimization, offset); return true; } @@ -534,12 +532,12 @@ bool SimpleTree::node_t::check_tiles(node_t* start, std::vector_low->is_leaf()); assert(_low->_high->is_leaf()); - _high->_low->_cost = _low->_high->midcost(*_high->_low, minval, maxval); + _high->_low->_cost = _low->_high->midcost(*_high->_low, best_val, worst_val); _var = _low->_var; _limit = _low->_limit; _low = _low->_low; // we could compute the values on the fly; but no time currently - check_tiles(start, nodes, bounds, val, minval, maxval, minimization, offset); + check_tiles(start, nodes, bounds, val, best_val, worst_val, minimization, offset); return true; } @@ -612,11 +610,7 @@ void SimpleTree::node_t::insert(std::vector& key, json& tree, size_t act assert(_var == std::numeric_limits::max()); _low = std::make_shared(); _high = std::make_shared(); - if(!minimize) - { - _low->_cost *= -1; - _high->_cost *= -1; - } + _low->_cost = _high->_cost = (minimize ? 1 : -1) * std::numeric_limits::infinity(); if(!std::isinf(_cost)) { std::swap(_low->_cost, _cost); @@ -720,10 +714,7 @@ void SimpleTree::node_t::insert(std::vector& key, json& tree, size_t act { auto tmp = std::make_shared(); tmp->_low = std::make_shared(); - if(!minimize) - { - tmp->_low->_cost *= -1; - } + tmp->_cost = tmp->_low->_cost = (minimize ? 1 : -1) * std::numeric_limits::infinity(); tmp->_high = shared_from_this(); tmp->_limit = action; tmp->_var = prefix; @@ -753,11 +744,7 @@ void SimpleTree::node_t::insert(std::vector& key, json& tree, size_t act assert(std::isinf(_high->_cost)); _high->_low = std::make_shared(); _high->_high = std::make_shared(); - if(!minimize) - { - _high->_low->_cost *= -1; - _high->_high->_cost *= -1; - } + _high->_low->_cost = _high->_high->_cost = (minimize ? 1 : -1) * std::numeric_limits::infinity(); _high->_limit = action; _high->_var = prefix; _high->_low->_parent = _high.get(); @@ -771,11 +758,7 @@ void SimpleTree::node_t::insert(std::vector& key, json& tree, size_t act { auto tmp = std::make_shared(); tmp->_low = std::make_shared(); - if(!minimize) - { - tmp->_low->_cost *= -1; - tmp->_high->_cost *= -1; - } + tmp->_low->_cost = tmp->_cost = (minimize ? 1 : -1) * std::numeric_limits::infinity(); tmp->_parent = this; tmp->_high = _high; _high = tmp; @@ -810,14 +793,34 @@ void SimpleTree::node_t::insert(std::vector& key, json& tree, size_t act { if(_limit == key[prefix]) { - _low->insert(key, tree, action, parent, prefix + 1, minimize, accuracy, exactness); + _low->insert(key, tree, action, parent, prefix + (_low->_var != _var ? 1 : 0), minimize, accuracy, exactness); } else { - if(_limit > key[prefix]) - _low->insert(key, tree, action, parent, prefix, minimize, accuracy, exactness); - else - _high->insert(key, tree, action, parent, prefix, minimize, accuracy, exactness); + const auto b = _limit < key[prefix]; + auto branch = (*this)[b]; + if(branch->_var != prefix) + { + // we need to inject a node here + auto next = std::make_shared(); + (*next)[false] = std::make_shared(); + (*next)[false]->_cost = next->_cost = (minimize ? 1 : -1) * std::numeric_limits::infinity(); + next->_parent = this; + next->_var = prefix; + next->_limit = key[prefix]; + // example + // original [0,10] | [11,20] made for element 10, + // we inject element 7, so we now get + // ([0-7] | [8-10] ) | [11,20 + // where the original low is moved to the high + // of the newly created node + (*next)[true] = branch; + (*this)[b] = next; + (*next)[true]->_parent = next.get(); + (*next)[false]->_parent = next.get(); + next->insert(key, tree, action, parent, prefix, minimize, accuracy, exactness); + } + else branch->insert(key, tree, action, parent, prefix, minimize, accuracy, exactness); } } consistent(key.size() + 1); @@ -1115,7 +1118,7 @@ bool SimpleTree::node_t::is_leaf() const { std::ostream& SimpleTree::print(std::ostream& stream) const { - //_root->print(stream, 0); + _root->print(stream, 0); return stream; } diff --git a/src/SimpleTree.h b/src/SimpleTree.h index b098234..bd9d5c6 100644 --- a/src/SimpleTree.h +++ b/src/SimpleTree.h @@ -38,7 +38,7 @@ class SimpleTree { public: SimpleTree(const SimpleTree& orig) = default; virtual ~SimpleTree() = default; - static SimpleTree parse(std::istream&, bool simplify = true, bool subsumption = true, double accuracy = 0); + static SimpleTree parse(std::istream&, bool simplify = false, bool subsumption = false, double accuracy = 0); static SimpleTree parse(std::istream&, bool simplify, bool subsumption, double accuracy, std::vector& exactness); std::ostream& print(std::ostream& stream) const; std::ostream& print_c(std::ostream& stream, std::string name) const; @@ -81,7 +81,7 @@ class SimpleTree { void action_nodes(std::vector>& nodes, uint32_t low, uint32_t high, uint32_t varid); std::pair compute_min_max(); bool check_tiles(node_t* start, std::vector>& , std::vector>& bounds, double val, double minval, double maxval, bool minimization, size_t offset); - bool subsumes(std::vector>& bounds, std::vector>& obounds, double val, bool minimization, size_t offset, double& best, std::pair& closest); + bool subsumes(const std::vector>& bounds, std::vector>& obounds, const double val, const bool minimization, size_t offset, double& best, std::pair& closest); void get_ranks(std::set>& values, node_t* start); void set_ranks(std::unordered_map& values); std::ostream& print_c(std::ostream& stream, size_t disc, std::unordered_set& printed, size_t tabs = 0) const; @@ -113,6 +113,9 @@ class SimpleTree { return _low < other._low; return _high < other._high; } + std::shared_ptr& operator[](bool b) { + return b ? _high : _low; + } }; std::vector _actions; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..3417e26 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,18 @@ + +find_package (Boost COMPONENTS unit_test_framework REQUIRED) +include_directories (${TEST_SOURCE_DIR}/src + ${Boost_INCLUDE_DIRS} + ${libstrategy_SOURCE_DIR} + ) +add_definitions (-DBOOST_TEST_DYN_LINK) + +add_executable (unordered_load unordered_load.cpp) +add_executable (inconsistent_lookup inconsistent_lookup.cpp) + +target_link_libraries(unordered_load ${Boost_LIBRARIES} strategy) +target_link_libraries(inconsistent_lookup ${Boost_LIBRARIES} strategy) + +add_test(NAME unordered_load COMMAND unordered_load) +add_test(NAME inconsistent_lookup COMMAND inconsistent_lookup) +set_tests_properties(inconsistent_lookup PROPERTIES + ENVIRONMENT STRATEGY_DIR=${CMAKE_CURRENT_SOURCE_DIR}/strategies) diff --git a/test/inconsistent_lookup.cpp b/test/inconsistent_lookup.cpp new file mode 100644 index 0000000..c5ef33b --- /dev/null +++ b/test/inconsistent_lookup.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Peter G. Jensen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#define BOOST_TEST_MODULE UnorderedLoad + +#include +#include + +#include "SimpleTree.h" + +BOOST_AUTO_TEST_CASE(DirectoryTest) +{ + BOOST_REQUIRE(getenv("STRATEGY_DIR")); +} + +BOOST_AUTO_TEST_CASE(Inconsistent1) +{ + std::string strategy = getenv("STRATEGY_DIR"); + strategy += "/inconsistent1.strategy"; + std::ifstream in(strategy); + auto tree = SimpleTree::parse(in, false, false); + double vars[] = {10}; + auto act18 = tree.value(vars,nullptr, 0); + auto act19 = tree.value(vars,nullptr, 1); + BOOST_REQUIRE_LT(act18, act19); +} + +BOOST_AUTO_TEST_CASE(Inconsistent1Simplify) +{ + std::string strategy = getenv("STRATEGY_DIR"); + strategy += "/inconsistent1.strategy"; + std::ifstream in(strategy); + auto tree = SimpleTree::parse(in, true, false); + double vars[] = {10}; + BOOST_REQUIRE_LT(tree.value(vars,nullptr, 0), tree.value(vars,nullptr, 1)); +} + +BOOST_AUTO_TEST_CASE(Inconsistent1SimplifySubsumption) +{ + std::string strategy = getenv("STRATEGY_DIR"); + strategy += "/inconsistent1.strategy"; + std::ifstream in(strategy); + auto tree = SimpleTree::parse(in, true, true); + double vars[] = {10}; + BOOST_REQUIRE_LT(tree.value(vars,nullptr, 0), tree.value(vars,nullptr, 1)); +} diff --git a/test/strategies/inconsistent1.strategy b/test/strategies/inconsistent1.strategy new file mode 100644 index 0000000..2c70763 --- /dev/null +++ b/test/strategies/inconsistent1.strategy @@ -0,0 +1,95 @@ +{"version":1.0,"type":"state->regressor","representation":"map","actions":{ + "0":"movement0.P0->movement0.F0T1 { isReady(id, 0, 1), tau, t := 0, position[id] := -1, punish(id, 0, 1) }", + "1":"movement0.P0->movement0.F0T2 { isReady(id, 0, 2), tau, t := 0, position[id] := -1, punish(id, 0, 2) }" + },"statevars":[ + "taskExe1.location" + ],"pointvars":[ + ],"locationnames":{ + "movement0.location":{ + "0":"P0", + "1":"F0T1", + "2":"F0T2", + "3":"F0T3", + "4":"P1", + "5":"F1T2", + "6":"F1T3", + "7":"P2", + "8":"F2T1", + "9":"F2T3", + "10":"P3", + "11":"F3T1", + "12":"F3T2" + }, + "taskExe0.location":{ + "0":"Waiting", + "1":"T0", + "2":"T1", + "3":"T2", + "4":"T3" + }, + "movement1.location":{ + "0":"P0", + "1":"F0T1", + "2":"F0T2", + "3":"F0T3", + "4":"P1", + "5":"F1T2", + "6":"F1T3", + "7":"P2", + "8":"F2T1", + "9":"F2T3", + "10":"P3", + "11":"F3T1", + "12":"F3T2" + }, + "taskExe1.location":{ + "0":"Waiting", + "1":"T0", + "2":"T1", + "3":"T2", + "4":"T3" + }, + "movement2.location":{ + "0":"P0", + "1":"F0T1", + "2":"F0T2", + "3":"F0T3", + "4":"P1", + "5":"F1T2", + "6":"F1T3", + "7":"P2", + "8":"F2T1", + "9":"F2T3", + "10":"P3", + "11":"F3T1", + "12":"F3T2" + }, + "taskExe2.location":{ + "0":"Waiting", + "1":"T0", + "2":"T1", + "3":"T2", + "4":"T3" + } + },"regressors":{ + "(4)": + {"type":"act->point->val","representation":"simpletree","minimize":0,"regressor": + { + "0" : -58.52619021830245 + } + }, + "(2)": + {"type":"act->point->val","representation":"simpletree","minimize":0,"regressor": + { + "1" : -104.5393376817416 + } + }, + "(10)": + {"type":"act->point->val","representation":"simpletree","minimize":0,"regressor": + { + "0" : -39.75, + "1" : -26.30381528710121 + } + } + } +} diff --git a/test/unordered_load.cpp b/test/unordered_load.cpp new file mode 100644 index 0000000..4589c50 --- /dev/null +++ b/test/unordered_load.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2021 Peter G. Jensen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#define BOOST_TEST_MODULE UnorderedLoad + +#include + +#include "SimpleTree.h" + + +const std::string simple_unordered_strategy = "{\"version\":1.0,\"type\":\"state->regressor\",\"representation\":\"map\",\"actions\":{" +" \"0\":\"Controller._id4->Controller._id2 { 1, tau, minute_clock := TIME_OFFSET, initValues() }\"," +" \"1\":\"Controller._id2->Controller.Wait { 0 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 0, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"2\":\"Controller._id2->Controller.Wait { 1 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 1, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"3\":\"Controller._id2->Controller.Wait { 2 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 2, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"4\":\"Controller._id2->Controller.Wait { 3 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 3, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"5\":\"Controller._id2->Controller.Wait { 4 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 4, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"6\":\"Controller._id2->Controller.Wait { 5 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 5, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"7\":\"Controller._id2->Controller.Wait { 6 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 6, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"9\":\"Controller._id2->Controller.Wait { 8 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 8, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"10\":\"Controller._id2->Controller.Wait { 9 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 9, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"11\":\"Controller._id2->Controller.Wait { 10 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 10, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"12\":\"Controller._id2->Controller.Wait { 1, tau, consumed_power := 0, heat_produced := 0 }\"," +" \"13\":\"WAIT\"" +"},\"statevars\":[" +" \"round(minute_clock) \"" +"],\"pointvars\":[" +"],\"locationnames\":{" +" \"Fetch_Data.location\":{" +" \"0\":\"_id5\"" +" }," +" \"Room1.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room2.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room3.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room4.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Optimization.location\":{" +" \"0\":\"_id1\"" +" }," +" \"Controller.location\":{" +" \"0\":\"_id2\"," +" \"1\":\"Wait\"," +" \"2\":\"_id4\"" +" }" +"},\"regressors\":{" +" \"(30)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.294636921229531," +" \"12\" : 3.091107032150207" +" }" +" }," +" \"(210)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.009248500699941," +" \"12\" : 1.028772620412916" +" }" +" }," +" \"(15)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 2.855407148131672," +" \"12\" : 1.352930166302546" +" }" +" }" +" }" +"}"; + + + + +const std::string unordered_strategy = "{\"version\":1.0,\"type\":\"state->regressor\",\"representation\":\"map\",\"actions\":{" +" \"0\":\"Controller._id4->Controller._id2 { 1, tau, minute_clock := TIME_OFFSET, initValues() }\"," +" \"1\":\"Controller._id2->Controller.Wait { 0 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 0, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"2\":\"Controller._id2->Controller.Wait { 1 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 1, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"3\":\"Controller._id2->Controller.Wait { 2 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 2, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"4\":\"Controller._id2->Controller.Wait { 3 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 3, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"5\":\"Controller._id2->Controller.Wait { 4 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 4, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"6\":\"Controller._id2->Controller.Wait { 5 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 5, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"7\":\"Controller._id2->Controller.Wait { 6 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 6, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"9\":\"Controller._id2->Controller.Wait { 8 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 8, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"10\":\"Controller._id2->Controller.Wait { 9 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 9, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"11\":\"Controller._id2->Controller.Wait { 10 >= 10 && any_on(), tau, consumed_power := 0.625000 + 0.187500 * 10, heat_produced := consumed_power * calculateCOP(), setMassFlow() }\"," +" \"12\":\"Controller._id2->Controller.Wait { 1, tau, consumed_power := 0, heat_produced := 0 }\"," +" \"13\":\"WAIT\"" +"},\"statevars\":[" +" \"round(minute_clock) \"" +"],\"pointvars\":[" +"],\"locationnames\":{" +" \"Fetch_Data.location\":{" +" \"0\":\"_id5\"" +" }," +" \"Room1.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room2.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room3.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Room4.location\":{" +" \"0\":\"_id0\"" +" }," +" \"Optimization.location\":{" +" \"0\":\"_id1\"" +" }," +" \"Controller.location\":{" +" \"0\":\"_id2\"," +" \"1\":\"Wait\"," +" \"2\":\"_id4\"" +" }" +"},\"regressors\":{" +" \"(195)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.767005809675129," +" \"12\" : 0.5472758743181302" +" }" +" }," +" \"(180)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 2.107357559876886," +" \"12\" : 0.841995896951961" +" }" +" }," +" \"(225)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 0.3895094003837855," +" \"12\" : 1.438914715299473" +" }" +" }," +" \"(120)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 3.562263183988571," +" \"12\" : 3.01531941566271" +" }" +" }," +" \"(90)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 4.595961684754502," +" \"12\" : 4.520572775155376" +" }" +" }," +" \"(75)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 5.200779712113728," +" \"12\" : 1.1120904838198" +" }" +" }," +" \"(165)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 2.422010195182813," +" \"12\" : 1.850311355224428" +" }" +" }," +" \"(240)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 0.1842626478060555," +" \"12\" : 0.5429048553483474" +" }" +" }," +" \"(150)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.802785410011689," +" \"12\" : 2.744820174794056" +" }" +" }," +" \"(135)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 4.082210512180363," +" \"12\" : 1.046474095029413" +" }" +" }," +" \"(105)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 3.506084076677214," +" \"12\" : 4.529894227895771" +" }" +" }," +" \"(45)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 2.923974662511487," +" \"12\" : 3.712782046133843" +" }" +" }," +" \"(30)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.294636921229531," +" \"12\" : 3.091107032150207" +" }" +" }," +" \"(210)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 1.009248500699941," +" \"12\" : 1.028772620412916" +" }" +" }," +" \"(15)\":" +" {\"type\":\"act->point->val\",\"representation\":\"simpletree\",\"minimize\":1,\"regressor\":" +" {" +" \"11\" : 2.855407148131672," +" \"12\" : 1.352930166302546" +" }" +" }" +" }" +"}"; + + + +BOOST_AUTO_TEST_CASE(SimpleUnorderedKeyLoad) +{ + std::stringstream ss(simple_unordered_strategy); + auto strategy = SimpleTree::parse(ss, false, false, 0); + double disc[1] = {15.0}; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 2.855407148131672); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 1.352930166302546); + + disc[0] = 210; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 1.009248500699941); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 1.028772620412916); + + disc[0] = 30; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 1.294636921229531); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 3.091107032150207); +} + +BOOST_AUTO_TEST_CASE(UnorderedKeyLoad) +{ + std::stringstream ss(unordered_strategy); + auto strategy = SimpleTree::parse(ss, false, false, 0); + double disc[1] = {15.0}; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 2.855407148131672); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 1.352930166302546); + + disc[0] = 210; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 1.009248500699941); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 1.028772620412916); + + disc[0] = 30; + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 11), 1.294636921229531); + BOOST_CHECK_EQUAL(strategy.value(disc, nullptr, 12), 3.091107032150207); +}