diff --git a/lib/coek/coek/api/expression.cpp b/lib/coek/coek/api/expression.cpp index 50cd4e7c..fc487e06 100644 --- a/lib/coek/coek/api/expression.cpp +++ b/lib/coek/coek/api/expression.cpp @@ -56,6 +56,10 @@ Parameter parameter() { return Parameter(); } Parameter parameter(const std::string& name) { return Parameter(name); } +Parameter data() { return Parameter(); } + +Parameter data(const std::string& name) { return Parameter(name); } + // // IndexParameter // diff --git a/lib/coek/coek/api/expression.hpp b/lib/coek/coek/api/expression.hpp index d21b43f3..74f70040 100644 --- a/lib/coek/coek/api/expression.hpp +++ b/lib/coek/coek/api/expression.hpp @@ -153,6 +153,8 @@ class Parameter { Parameter parameter(); Parameter parameter(const std::string& name); +Parameter data(); +Parameter data(const std::string& name); // Index Parameter class IndexParameter { diff --git a/lib/coek/coek/ast/visitor_eval.cpp b/lib/coek/coek/ast/visitor_eval.cpp index 7ddd338b..c00dc863 100644 --- a/lib/coek/coek/ast/visitor_eval.cpp +++ b/lib/coek/coek/ast/visitor_eval.cpp @@ -70,6 +70,13 @@ double visit_VariableTerm(const expr_pointer_t& expr, VariableData& data) } #ifdef COEK_WITH_COMPACT_MODEL +double visit_VariableRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) +{ + throw std::runtime_error( + "Cannot evaluate an expression that contains a VariableRefTerm. This is an abstract " + "expression!"); +} + double visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) { throw std::runtime_error( @@ -77,10 +84,10 @@ double visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*da "expression!"); } -double visit_VariableRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) +double visit_DataRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) { throw std::runtime_error( - "Cannot evaluate an expression that contains a VariableRefTerm. This is an abstract " + "Cannot evaluate an expression that contains a DataRefTerm. This is an abstract " "expression!"); } #endif @@ -205,6 +212,7 @@ double visit_expression(const expr_pointer_t& expr, VariableData& data) #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_mutable_values.cpp b/lib/coek/coek/ast/visitor_mutable_values.cpp index 5919d144..e0f91b73 100644 --- a/lib/coek/coek/ast/visitor_mutable_values.cpp +++ b/lib/coek/coek/ast/visitor_mutable_values.cpp @@ -71,9 +71,11 @@ void visit_VariableTerm(const expr_pointer_t& expr, MutableValuesData& data) } #ifdef COEK_WITH_COMPACT_MODEL +void visit_VariableRefTerm(const expr_pointer_t& /*expr*/, MutableValuesData& /*data*/) {} + void visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, MutableValuesData& /*data*/) {} -void visit_VariableRefTerm(const expr_pointer_t& /*expr*/, MutableValuesData& /*data*/) {} +void visit_DataRefTerm(const expr_pointer_t& /*expr*/, MutableValuesData& /*data*/) {} #endif void visit_MonomialTerm(const expr_pointer_t& expr, MutableValuesData& data) @@ -183,6 +185,7 @@ void visit_expression(const expr_pointer_t& expr, MutableValuesData& data) #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_simplify.cpp b/lib/coek/coek/ast/visitor_simplify.cpp index 2584d61d..a9f66fcd 100644 --- a/lib/coek/coek/ast/visitor_simplify.cpp +++ b/lib/coek/coek/ast/visitor_simplify.cpp @@ -78,13 +78,19 @@ void visit_VariableTerm(const expr_pointer_t& expr, VisitorData& data) } #ifdef COEK_WITH_COMPACT_MODEL +void visit_VariableRefTerm(const expr_pointer_t& expr, VisitorData& data) +{ + data.last_expr = expr; + data.is_value = false; +} + void visit_ParameterRefTerm(const expr_pointer_t& expr, VisitorData& data) { data.last_expr = expr; data.is_value = false; } -void visit_VariableRefTerm(const expr_pointer_t& expr, VisitorData& data) +void visit_DataRefTerm(const expr_pointer_t& expr, VisitorData& data) { data.last_expr = expr; data.is_value = false; @@ -416,6 +422,7 @@ void visit_expression(const expr_pointer_t& expr, VisitorData& data) #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_symdiff.cpp b/lib/coek/coek/ast/visitor_symdiff.cpp index 79da37c7..b7116684 100644 --- a/lib/coek/coek/ast/visitor_symdiff.cpp +++ b/lib/coek/coek/ast/visitor_symdiff.cpp @@ -58,11 +58,6 @@ void visit_VariableTerm(const expr_pointer_t& /*expr*/, PartialData& data) } #ifdef COEK_WITH_COMPACT_MODEL -void visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, PartialData& data) -{ - data.partial = ZEROCONST; -} - // // We assume for now that a user cannot differentiate with respect to an referenced // variable. It's not clear that we can infer whether two referenced variables are the same, @@ -72,6 +67,16 @@ void visit_VariableRefTerm(const expr_pointer_t& /*expr*/, PartialData& data) { data.partial = ZEROCONST; } + +void visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, PartialData& data) +{ + data.partial = ZEROCONST; +} + +void visit_DataRefTerm(const expr_pointer_t& /*expr*/, PartialData& data) +{ + data.partial = ZEROCONST; +} #endif void visit_MonomialTerm(const expr_pointer_t& expr, PartialData& data) @@ -278,6 +283,7 @@ expr_pointer_t compute_partial(const expr_pointer_t& expr, size_t i, PartialData #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_to_MutableNLPExpr.cpp b/lib/coek/coek/ast/visitor_to_MutableNLPExpr.cpp index d22530ac..2a6039f9 100644 --- a/lib/coek/coek/ast/visitor_to_MutableNLPExpr.cpp +++ b/lib/coek/coek/ast/visitor_to_MutableNLPExpr.cpp @@ -108,6 +108,18 @@ void visit(std::shared_ptr& /*expr*/, MutableNLPExpr& /*repn*/, { throw std::runtime_error("Unexpected variable reference."); } + +void visit(std::shared_ptr& /*expr*/, MutableNLPExpr& /*repn*/, + double /*multiplier*/) +{ + throw std::runtime_error("Unexpected parameter reference."); +} + +void visit(std::shared_ptr& /*expr*/, MutableNLPExpr& /*repn*/, + double /*multiplier*/) +{ + throw std::runtime_error("Unexpected data reference."); +} #endif void visit(std::shared_ptr& expr, MutableNLPExpr& repn, double multiplier) @@ -438,6 +450,8 @@ void visit_expression(const expr_pointer_t& expr, MutableNLPExpr& repn, double m VISIT_CASE(VariableTerm); #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); + VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_to_QuadraticExpr.cpp b/lib/coek/coek/ast/visitor_to_QuadraticExpr.cpp index 26cad265..22052be6 100644 --- a/lib/coek/coek/ast/visitor_to_QuadraticExpr.cpp +++ b/lib/coek/coek/ast/visitor_to_QuadraticExpr.cpp @@ -76,6 +76,18 @@ void visit(std::shared_ptr& /*expr*/, QuadraticExpr& /*repn*/, { throw std::runtime_error("Unexpected variable reference."); } + +void visit(std::shared_ptr& /*expr*/, QuadraticExpr& /*repn*/, + double /*multiplier*/) +{ + throw std::runtime_error("Unexpected parameter reference."); +} + +void visit(std::shared_ptr& /*expr*/, QuadraticExpr& /*repn*/, + double /*multiplier*/) +{ + throw std::runtime_error("Unexpected data reference."); +} #endif void visit(std::shared_ptr& expr, QuadraticExpr& repn, double multiplier) @@ -369,6 +381,8 @@ void visit_expression(const expr_pointer_t& expr, QuadraticExpr& repn, double mu VISIT_CASE(VariableTerm); #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); + VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_to_list.cpp b/lib/coek/coek/ast/visitor_to_list.cpp index f66740ee..2fd90e3f 100644 --- a/lib/coek/coek/ast/visitor_to_list.cpp +++ b/lib/coek/coek/ast/visitor_to_list.cpp @@ -48,6 +48,14 @@ void visit_VariableTerm(const expr_pointer_t& expr, std::list& repr } #ifdef COEK_WITH_COMPACT_MODEL +void visit_VariableRefTerm(const expr_pointer_t& expr, std::list& repr) +{ + auto tmp = safe_pointer_cast(expr); + std::stringstream sstr; + write_expr(tmp, sstr); + repr.push_back(sstr.str()); +} + void visit_ParameterRefTerm(const expr_pointer_t& expr, std::list& repr) { auto tmp = safe_pointer_cast(expr); @@ -56,9 +64,9 @@ void visit_ParameterRefTerm(const expr_pointer_t& expr, std::list& repr.push_back(sstr.str()); } -void visit_VariableRefTerm(const expr_pointer_t& expr, std::list& repr) +void visit_DataRefTerm(const expr_pointer_t& expr, std::list& repr) { - auto tmp = safe_pointer_cast(expr); + auto tmp = safe_pointer_cast(expr); std::stringstream sstr; write_expr(tmp, sstr); repr.push_back(sstr.str()); @@ -276,6 +284,7 @@ void visit_expression(const expr_pointer_t& expr, std::list& repr) #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_variables.cpp b/lib/coek/coek/ast/visitor_variables.cpp index 1aa6722b..4051970a 100644 --- a/lib/coek/coek/ast/visitor_variables.cpp +++ b/lib/coek/coek/ast/visitor_variables.cpp @@ -75,12 +75,17 @@ void visit_VariableTerm(const expr_pointer_t& expr, VariableData& data) } #ifdef COEK_WITH_COMPACT_MODEL +void visit_VariableRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) +{ + throw std::runtime_error("Attempting to find variables in an abstract expression!"); +} + void visit_ParameterRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) { throw std::runtime_error("Attempting to find variables in an abstract expression!"); } -void visit_VariableRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) +void visit_DataRefTerm(const expr_pointer_t& /*expr*/, VariableData& /*data*/) { throw std::runtime_error("Attempting to find variables in an abstract expression!"); } @@ -195,6 +200,7 @@ void visit_expression(const expr_pointer_t& expr, VariableData& data) #ifdef COEK_WITH_COMPACT_MODEL VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); diff --git a/lib/coek/coek/ast/visitor_write_expr.cpp b/lib/coek/coek/ast/visitor_write_expr.cpp index 59cae23a..9eab0c37 100644 --- a/lib/coek/coek/ast/visitor_write_expr.cpp +++ b/lib/coek/coek/ast/visitor_write_expr.cpp @@ -49,6 +49,26 @@ void visit_VariableTerm(const expr_pointer_t& expr, std::ostream& ostr) } #ifdef COEK_WITH_COMPACT_MODEL +void visit_VariableRefTerm(const expr_pointer_t& expr, std::ostream& ostr) +{ + auto tmp = safe_pointer_cast(expr); + bool first = true; + ostr << tmp->name << "["; + for (auto& val : tmp->indices) { + if (first) + first = false; + else + ostr << ","; + if (auto ival = std::get_if(&val)) { + ostr << *ival; + } + else if (auto eval = std::get_if(&val)) { + visit_expression(*eval, ostr); + } + } + ostr << "]"; +} + void visit_ParameterRefTerm(const expr_pointer_t& expr, std::ostream& ostr) { auto tmp = safe_pointer_cast(expr); @@ -69,9 +89,9 @@ void visit_ParameterRefTerm(const expr_pointer_t& expr, std::ostream& ostr) ostr << "]"; } -void visit_VariableRefTerm(const expr_pointer_t& expr, std::ostream& ostr) +void visit_DataRefTerm(const expr_pointer_t& expr, std::ostream& ostr) { - auto tmp = safe_pointer_cast(expr); + auto tmp = safe_pointer_cast(expr); bool first = true; ostr << tmp->name << "["; for (auto& val : tmp->indices) { @@ -271,8 +291,9 @@ void visit_expression(const expr_pointer_t& expr, std::ostream& ostr) VISIT_CASE(IndexParameterTerm); VISIT_CASE(VariableTerm); #ifdef COEK_WITH_COMPACT_MODEL - VISIT_CASE(ParameterRefTerm); VISIT_CASE(VariableRefTerm); + VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); diff --git a/lib/coek/coek/coek.hpp b/lib/coek/coek/coek.hpp index 8ffd3bf9..73301d67 100644 --- a/lib/coek/coek/coek.hpp +++ b/lib/coek/coek/coek.hpp @@ -17,6 +17,7 @@ #include "coek/api/objective.hpp" #ifdef __cpp_lib_variant # include "coek/api/parameter_array.hpp" +# include "coek/api/data_array.hpp" # include "coek/api/variable_array.hpp" # include "coek/api/constraint_map.hpp" # include "coek/api/subexpression_map.hpp" @@ -31,6 +32,7 @@ # include "coek/compact/expression_sequence.hpp" # include "coek/compact/objective_sequence.hpp" # include "coek/compact/parameter_map.hpp" +# include "coek/compact/data_map.hpp" # include "coek/compact/sequence_context.hpp" # include "coek/compact/variable_map.hpp" # include "coek/model/compact_model.hpp" diff --git a/lib/coek/coek/compact/visitor_exprtemplate.cpp b/lib/coek/coek/compact/visitor_exprtemplate.cpp index 0c34b14f..07d747c4 100644 --- a/lib/coek/coek/compact/visitor_exprtemplate.cpp +++ b/lib/coek/coek/compact/visitor_exprtemplate.cpp @@ -33,16 +33,22 @@ expr_pointer_t visit_IndexParameterTerm(const expr_pointer_t& expr) "value."); } +expr_pointer_t visit_VariableRefTerm(const expr_pointer_t& expr) +{ + auto tmp = safe_pointer_cast(expr); + return tmp->get_concrete_variable(); +} + expr_pointer_t visit_ParameterRefTerm(const expr_pointer_t& expr) { auto tmp = safe_pointer_cast(expr); return tmp->get_concrete_parameter(); } -expr_pointer_t visit_VariableRefTerm(const expr_pointer_t& expr) +expr_pointer_t visit_DataRefTerm(const expr_pointer_t& expr) { - auto tmp = safe_pointer_cast(expr); - return tmp->get_concrete_variable(); + auto tmp = safe_pointer_cast(expr); + return tmp->get_concrete_data(); } expr_pointer_t visit_ObjectiveTerm(const expr_pointer_t& expr) @@ -217,6 +223,7 @@ expr_pointer_t visit_expression(const expr_pointer_t& expr) // VISIT_CASE(VariableTerm); VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); // VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); VISIT_CASE(StrictInequalityTerm); diff --git a/lib/coek/coek/model/writer_nl.cpp b/lib/coek/coek/model/writer_nl.cpp index cfb2a231..6beb8215 100644 --- a/lib/coek/coek/model/writer_nl.cpp +++ b/lib/coek/coek/model/writer_nl.cpp @@ -67,6 +67,7 @@ void visit_expression(const expr_pointer_t& expr, VisitorType& data) #if __cpp_lib_variant VISIT_CASE(VariableRefTerm); VISIT_CASE(ParameterRefTerm); + VISIT_CASE(DataRefTerm); #endif VISIT_CASE(MonomialTerm); VISIT_CASE(InequalityTerm); @@ -120,6 +121,12 @@ inline void visit_IndexParameterTerm(const expr_pointer_t&, TYPE&) } #if __cpp_lib_variant +template +inline void visit_VariableRefTerm(const expr_pointer_t&, TYPE&) +{ + throw std::runtime_error("Cannot write an NL file using an abstract expression!"); +} + template inline void visit_ParameterRefTerm(const expr_pointer_t&, TYPE&) { @@ -127,7 +134,7 @@ inline void visit_ParameterRefTerm(const expr_pointer_t&, TYPE&) } template -inline void visit_VariableRefTerm(const expr_pointer_t&, TYPE&) +inline void visit_DataRefTerm(const expr_pointer_t&, TYPE&) { throw std::runtime_error("Cannot write an NL file using an abstract expression!"); } diff --git a/lib/coek/test/CMakeLists.txt b/lib/coek/test/CMakeLists.txt index 882cf48a..f81c70d3 100644 --- a/lib/coek/test/CMakeLists.txt +++ b/lib/coek/test/CMakeLists.txt @@ -24,6 +24,7 @@ SET(sources smoke/test_indexed.cpp smoke/test_var.cpp smoke/test_param.cpp + smoke/test_data.cpp smoke/test_expr.cpp smoke/test_obj.cpp smoke/test_con.cpp diff --git a/lib/coek/test/smoke/test_data.cpp b/lib/coek/test/smoke/test_data.cpp new file mode 100644 index 00000000..15c5d8ae --- /dev/null +++ b/lib/coek/test/smoke/test_data.cpp @@ -0,0 +1,884 @@ + +#include +#include +#include +#include + +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers.hpp" +#include "coek/ast/base_terms.hpp" +#include "coek/ast/value_terms.hpp" +#include "coek/coek.hpp" + +const double E = exp(1.0); + +TEST_CASE("elementary_data", "[smoke]") +{ + SECTION("values") + { + WHEN("data - 3") + { + auto q = coek::data("q").value(2); + REQUIRE(q.value() == 2); + q.value(3); + REQUIRE(q.value() == 3); + } + WHEN("data - p+1") + { + auto p = coek::data("p").value(3); + auto q = coek::data("q").value(2); + REQUIRE(q.value() == 2); + q.value(p + 1); + REQUIRE(q.value() == 4); + } + } + + SECTION("constructors") + { + WHEN("copy") + { + // Simple constructor + auto q = coek::data().value(3); + + // Test copy constructor + coek::Parameter Q(q); + REQUIRE(Q.value() == 3); + } + + WHEN("equal") + { + // Simple constructor + auto q = coek::data().value(4); + + // Test copy constructor + auto Q = coek::data().value(5); + Q = q; + REQUIRE(Q.value() == 4); + } + } + + SECTION("constructors") + { + auto q = coek::data("q").value(3); + REQUIRE(q.name() == "q"); + } + + SECTION("write") + { + std::stringstream sstr; + auto q = coek::data("q").value(3); + sstr << q; + REQUIRE(sstr.str() == "q"); + } +} + +TEST_CASE("model_indexdata", "[smoke]") +{ + SECTION("values") + { + WHEN("IndexParameter - 3") + { + auto q = coek::set_element("q"); + q.value(1); + int tmp = -1; + auto success = q.get_value(tmp); + REQUIRE(success == true); + REQUIRE(tmp == 1); + q.value(3.5); + success = q.get_value(tmp); + REQUIRE(success == false); + } + WHEN("IndexParameter - 3.5") + { + auto q = coek::set_element(); + q.value(3.5); + double tmp = -3.5; + auto success = q.get_value(tmp); + REQUIRE(success == true); + REQUIRE(tmp == 3.5); + q.value(3); + success = q.get_value(tmp); + REQUIRE(success == false); + } + WHEN("IndexParameter - 'here'") + { + auto q = coek::set_element(); + q.value("here"); + std::string tmp = "there"; + auto success = q.get_value(tmp); + REQUIRE(success == true); + REQUIRE(tmp == "here"); + q.value(3.5); + success = q.get_value(tmp); + REQUIRE(success == false); + } + } + + SECTION("constructors") + { + WHEN("copy") + { + // Simple constructor + auto q = coek::set_element(); + q.value(3); + + // Test copy constructor + coek::IndexParameter Q(q); + int tmp = -1; + auto success = Q.get_value(tmp); + REQUIRE(success == true); + REQUIRE(tmp == 3); + } + + WHEN("equal") + { + // Simple constructor + auto q = coek::set_element(); + q.value(4); + + // Test copy constructor + auto Q = coek::set_element(); + Q.value(5); + Q = q; + int tmp = -1; + auto success = Q.get_value(tmp); + REQUIRE(success == true); + REQUIRE(tmp == 4); + } + } + + SECTION("constructors") + { + auto q = coek::set_element("q"); + REQUIRE(q.name() == "q"); + } + + SECTION("write") + { + std::stringstream sstr; + auto q = coek::set_element("q"); + sstr << q; + REQUIRE(sstr.str() == "q"); + } + + SECTION("name") + { + auto p = coek::set_element(); + auto q = coek::set_element("q"); + REQUIRE(p.name() == "unknown"); + p.name("P"); + REQUIRE(p.name() == "P"); + REQUIRE(q.name() == "q"); + } +} + +#ifdef COEK_WITH_COMPACT_MODEL +TEST_CASE("1D_data_map", "[smoke]") +{ + SECTION("int") + { + std::vector v = {1, 5, 3, 7}; + + WHEN("constructors") + { + auto s = coek::SetOf(v); + auto v1 = coek::data(s); + REQUIRE(v1.size() == 4); + auto v2 = coek::data("v2", s); + REQUIRE(v2.size() == 4); + auto v3 = coek::data_map(s); + REQUIRE(v3.size() == 4); + auto v4 = coek::data_map("v4", s); + REQUIRE(v4.size() == 4); + } + + WHEN("size") + { + auto s = coek::SetOf(v); + auto dats = coek::data(s); + REQUIRE(dats.size() == 4); + } + + WHEN("typeof") + { + auto s = coek::SetOf(v); + auto dats = coek::data(s); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + } + + WHEN("value - 1") + { + auto s = coek::SetOf(v); + auto dats = coek::data(s).value(1); + REQUIRE(dats(5).value() == 1); + } + } + + SECTION("int_ranged") + { + std::vector v = {1, 3, 5, 7}; + auto s = coek::RangeSet(1, 7, 2); + + WHEN("size") + { + auto dats = coek::data(s); + REQUIRE(dats.size() == 4); + } + + WHEN("typeof") + { + auto dats = coek::data(s); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + } + } + + SECTION("abstract") + { + std::vector v = {1, 5, 3, 7}; + auto s = coek::SetOf(v); + auto r = coek::SetOf({0}); + auto S = s - r; + auto dats = coek::data("dats", S).value(0); + + WHEN("typeof") { REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); } + + WHEN("index1") + { + auto i = coek::set_element("i"); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + REQUIRE(typeid(dats(i)).name() == typeid(coek::Expression).name()); + } + + WHEN("index2") + { + auto v = coek::data(); + coek::Expression f = v; + auto e = dats(1); + //REQUIRE(e.name() == "dats[1]"); + // auto it = e.to_list().begin(); + // REQUIRE_THAT( *it, Catch::Matchers::StartsWith("dats") ); + } + + WHEN("index3") + { + auto i = coek::set_element("i"); + auto e = dats(i); + static std::list baseline = {"dats[i]"}; + REQUIRE(e.to_list() == baseline); + } + + WHEN("index4") + { + auto i = coek::set_element("i"); + auto e = dats(i + 1); + static std::list baseline = {"dats[i + 1]"}; + REQUIRE(e.to_list() == baseline); + } + } +} +#endif + +#if __cpp_lib_variant +TEST_CASE("1D_data_array", "[smoke]") +{ + SECTION("int_vector") + { + WHEN("constructors") + { + auto v1 = coek::data(4); + REQUIRE(v1.size() == 4); + auto v2 = coek::data("v2", 4); + REQUIRE(v2.size() == 4); + auto v3 = coek::data_array(4); + REQUIRE(v3.size() == 4); + auto v4 = coek::data_array("v4", 4); + REQUIRE(v4.size() == 4); + } + + WHEN("size") + { + auto dats = coek::data(4); + REQUIRE(dats.size() == 4); + } + + WHEN("typeof") + { + auto dats = coek::data(4); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + } + + WHEN("value - 1") + { + auto dats = coek::data(4); + + // Set value using template + dats.value(1); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 1); + + // Set value for all indices + dats.value(2); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 2); + } + #if 0 + WHEN("value - q") + { + auto dats = coek::data(4); + auto q = coek::data().value(2); + for (size_t i = 0; i < 4; i++) + dats(i).value(q + (int)i); // TODO - generalize API to include unsigned ints + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 2 + (int)i); + } + #endif + WHEN("value all - q") + { + auto dats = coek::data(4); + auto q = coek::data().value(2); + + // Set value using template + dats.value(q + (int)2); // TODO - generalize API to include unsigned ints + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 4); + + // Set value for all indices + dats.value(q + (int)3); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 5); + } + #if 0 + WHEN("name") + { + auto dats = coek::data(4); + + dats.name("v"); + for (int i = 0; i < 4; i++) + REQUIRE(dats(i).name() == "v[" + std::to_string(i) + "]"); + + // We don't need to call again. Names are automatically generated + // after the first time. + dats.name("w"); + for (int i = 0; i < 4; i++) + REQUIRE(dats(i).name() == "w[" + std::to_string(i) + "]"); + + dats.name(""); + for (int i = 0; i < 4; i++) + REQUIRE(dats(i).name()[0] == 'P'); + } + #endif + } + + SECTION("int_vector_dim") + { + std::vector dim{4}; + + WHEN("size") + { + auto dats = coek::data("v", dim); + REQUIRE(dats.size() == 4); + } + + WHEN("typeof") + { + auto dats = coek::data(dim); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + auto dats = coek::data(dim).value(1); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 1); + } + + #if 0 + WHEN("name") + { + auto dats = coek::data(dim).name("v"); + for (int i = 0; i < 4; i++) + REQUIRE(dats(i).name() == "v[" + std::to_string(i) + "]"); + } + #endif + } + + SECTION("int_initializer_list") + { + WHEN("size") + { + auto dats = coek::data("v", {4}); + REQUIRE(dats.size() == 4); + } + + WHEN("typeof") + { + auto dats = coek::data({4}); + REQUIRE(typeid(dats(1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + auto dats = coek::data({4}).value(1); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i).value() == 1); + } + + #if 0 + WHEN("name") + { + auto dats = coek::data({4}).name("v"); + for (int i = 0; i < 4; i++) + REQUIRE(dats(i).name() == "v[" + std::to_string(i) + "]"); + } + #endif + } +} +#endif + +#ifdef COEK_WITH_COMPACT_MODEL +TEST_CASE("2D_data_map", "[smoke]") +{ + SECTION("int") + { + std::vector v = {1, 5, 3, 7}; + std::vector w = {2, 6, 4, 8}; + + WHEN("constructors") + { + auto V = coek::SetOf(v); + auto W = coek::SetOf(w); + auto S = V * W; + auto v1 = coek::data(S); + REQUIRE(v1.size() == 16); + auto v2 = coek::data("v2", S); + REQUIRE(v2.size() == 16); + auto v3 = coek::data_map(S); + REQUIRE(v3.size() == 16); + auto v4 = coek::data_map("v4", S); + REQUIRE(v4.size() == 16); + } + + WHEN("size") + { + auto V = coek::SetOf(v); + auto W = coek::SetOf(w); + auto S = V * W; + auto dats = coek::data(S); + REQUIRE(dats.size() == 16); + } + + WHEN("typeof") + { + auto V = coek::SetOf(v); + auto W = coek::SetOf(w); + auto S = V * W; + auto dats = coek::data(S); + REQUIRE(typeid(dats(1, 2)).name() == typeid(coek::Expression).name()); + } + + WHEN("data_index_error") + { + auto V = coek::SetOf(v); + auto W = coek::SetOf(w); + auto dats = coek::data(V * W).name("x"); + REQUIRE(dats.dim() == 2); + REQUIRE_THROWS_WITH(dats(0), + "Unexpected index value: x is an 2-D data map but is being " + "indexed with 1 indices."); + } + } + + SECTION("abstract") + { + std::vector v = {1, 5, 3, 7}; + std::vector w = {2, 6, 4, 8}; + auto V = coek::SetOf(v); + auto W = coek::SetOf(w); + auto r = coek::SetOf({0}); + auto S = V * W; + auto dats = coek::data("dats", S).value(0); + + WHEN("typeof") { REQUIRE(typeid(dats(1, 2)).name() == typeid(coek::Expression).name()); } + + WHEN("index1") + { + auto i = coek::set_element("i"); + auto j = coek::set_element("j"); + REQUIRE(typeid(dats(1, 2)).name() == typeid(coek::Expression).name()); + REQUIRE(typeid(dats(10, 11)).name() == typeid(coek::Expression).name()); + REQUIRE(typeid(dats(i, j)).name() == typeid(coek::Expression).name()); + } + + #if 0 + WHEN("index2") + { + auto e = dats(1, 2); + REQUIRE(e.name() == "dats[1,2]"); + // auto it = e.to_list().begin(); + // REQUIRE_THAT( *it, Catch::Matchers::StartsWith("dats") ); + } + #endif + + WHEN("index3") + { + auto i = coek::set_element("i"); + auto j = coek::set_element("j"); + auto e = dats(i, j); + static std::list baseline = {"dats[i,j]"}; + REQUIRE(e.to_list() == baseline); + } + + WHEN("index4") + { + auto i = coek::set_element("i"); + auto j = coek::set_element("j"); + auto e = dats(i + 1, j - 1); + static std::list baseline = {"dats[i + 1,j + -1]"}; + REQUIRE(e.to_list() == baseline); + } + } +} +#endif + +#if __cpp_lib_variant +TEST_CASE("2D_data_array", "[smoke]") +{ + SECTION("int_vector_dim") + { + WHEN("constructors") + { + auto v1 = coek::data({4, 4}); + REQUIRE(v1.size() == 16); + auto v2 = coek::data("v2", {4, 4}); + REQUIRE(v2.size() == 16); + auto v3 = coek::data_array({4, 4}); + REQUIRE(v3.size() == 16); + auto v4 = coek::data_array("v4", {4, 4}); + REQUIRE(v4.size() == 16); + } + + WHEN("size") + { + std::vector dim{4, 3}; + auto dats = coek::data("v", dim); + REQUIRE(dats.size() == 12); + } + + WHEN("typeof") + { + std::vector dim{4, 3}; + auto dats = coek::data(dim); + REQUIRE(typeid(dats(1, 1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + std::vector dim{4, 5}; + auto dats = coek::data(dim).value(1); + for (size_t i = 0; i < 4; i++) + REQUIRE(dats(i, i).value() == 1); + } + + WHEN("index error") + { + std::vector dim{4, 3}; + auto dats = coek::data(dim).name("x"); + REQUIRE(dats.dim() == 2); + REQUIRE_THROWS_WITH(dats(0), + "Unexpected index value: x is an 2-D data array but is being " + "indexed with 1 indices."); + } + + #if 0 + WHEN("name") + { + std::vector dim{4, 3}; + auto dats = coek::data(dim).name("v"); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + REQUIRE(dats(i, j).name() + == "v[" + std::to_string(i) + "," + std::to_string(j) + "]"); + } + #endif + } + + SECTION("int_initializer_list") + { + WHEN("size") + { + auto dats = coek::data("v", {4, 3}); + REQUIRE(dats.size() == 12); + } + + WHEN("typeof") + { + auto dats = coek::data({4, 3}); + REQUIRE(typeid(dats(1, 1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + auto dats = coek::data({4, 3}).value(1); + for (size_t i = 0; i < 3; i++) + REQUIRE(dats(i, i).value() == 1); + } + + WHEN("index error") + { + auto dats = coek::data({4, 3}).name("x"); + REQUIRE(dats.dim() == 2); + REQUIRE_THROWS_WITH(dats(0), + "Unexpected index value: x is an 2-D data array but is being " + "indexed with 1 indices."); + } + + #if 0 + WHEN("name") + { + auto dats = coek::data({4, 3}).name("v"); + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + REQUIRE(dats(i, j).name() + == "v[" + std::to_string(i) + "," + std::to_string(j) + "]"); + } + #endif + } +} + +TEST_CASE("3D_data_array", "[smoke]") +{ + SECTION("int_vector_dim") + { + WHEN("constructors") + { + auto v1 = coek::data({5, 4, 3}); + REQUIRE(v1.size() == 60); + auto v2 = coek::data("v2", {5, 4, 3}); + REQUIRE(v2.size() == 60); + auto v3 = coek::data({5, 4, 3}); + REQUIRE(v3.size() == 60); + auto v4 = coek::data("v4", {5, 4, 3}); + REQUIRE(v4.size() == 60); + } + + WHEN("size") + { + std::vector dim{5, 4, 3}; + auto dats = coek::data("v", dim); + REQUIRE(dats.size() == 60); + } + + WHEN("typeof") + { + std::vector dim{5, 4, 3}; + auto dats = coek::data(dim); + REQUIRE(typeid(dats(1, 1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + std::vector dim{5, 4, 3}; + auto dats = coek::data(dim).value(1); + for (size_t i = 0; i < 3; i++) + REQUIRE(dats(i, i, i).value() == 1); + } + + WHEN("index error") + { + std::vector dim{5, 4, 3}; + auto dats = coek::data(dim).name("x"); + REQUIRE(dats.dim() == 3); + REQUIRE_THROWS_WITH(dats(0), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 1 indices."); + } + + #if 0 + WHEN("name") + { + std::vector dim{5, 4, 3}; + auto dats = coek::data(dim).name("v"); + for (int i = 0; i < 5; i++) + for (int j = 0; j < 4; j++) + for (int k = 0; k < 3; k++) + REQUIRE(dats(i, j, k).name() + == "v[" + std::to_string(i) + "," + std::to_string(j) + "," + + std::to_string(k) + "]"); + } + #endif + } + + SECTION("int_initializer_list") + { + WHEN("size") + { + auto dats = coek::data("v", {5, 4, 3}); + REQUIRE(dats.size() == 60); + } + + WHEN("typeof") + { + auto dats = coek::data({5, 4, 3}); + REQUIRE(typeid(dats(1, 1, 1)).name() == typeid(coek::Expression).name()); + } + + WHEN("index") + { + auto dats = coek::data({5, 4, 3}).value(1); + for (size_t i = 0; i < 3; i++) + REQUIRE(dats(i, i, i).value() == 1); + } + + WHEN("index error") + { + auto dats = coek::data({5, 4, 3}).name("x"); + REQUIRE(dats.dim() == 3); + REQUIRE_THROWS_WITH(dats(0), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 1 indices."); + } + + #if 0 + WHEN("name") + { + auto dats = coek::data({5, 4, 3}).name("v"); + for (int i = 0; i < 5; i++) + for (int j = 0; j < 4; j++) + for (int k = 0; k < 3; k++) + REQUIRE(dats(i, j, k).name() + == "v[" + std::to_string(i) + "," + std::to_string(j) + "," + + std::to_string(k) + "]"); + } + #endif + } +} +#endif + +#ifdef COEK_WITH_COMPACT_MODEL +TEST_CASE("3D_data_api", "[smoke]") +{ + SECTION("map") + { + std::vector vec = {1, 2, 3, 4}; + auto p = coek::data("p").value(1); + + WHEN("index api") + { + auto V = coek::SetOf(vec); + auto v = coek::data_map(V * V * V).name("x").value(1); + REQUIRE(v.size() == 64); + + int ival = 1; + size_t uval = 1; + auto e = p + 1; + // Misc tests to improve code coverage for the collect_args() methods + REQUIRE(v(e, uval, ival).expand().value() == 1); + + REQUIRE(v(uval, uval, e).expand().value() == 1); + + REQUIRE(v(ival, ival, e).expand().value() == 1); + + REQUIRE(v(uval, uval, uval).value() == 1); + + REQUIRE(v(ival, ival, ival).value() == 1); + + REQUIRE_THROWS_WITH(v(uval, uval), + "Unexpected index value: x is an 3-D data map but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(ival, ival), + "Unexpected index value: x is an 3-D data map but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(e, ival), + "Unexpected index value: x is an 3-D data map but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(ival, ival, -1), "Unknown index value: x[1,1,-1]"); + } + + WHEN("data value") + { + auto q = coek::data("q").value(1); + auto V = coek::SetOf(vec); + auto v = coek::data_map(V).name("x").value(1); + + REQUIRE(v(1).value() == 1); + v.value(q + 1); + REQUIRE(v(1).value() == 2); + q.value(2); + // Changing the value of q does *not* impact the value of v(1), since + // this is data and not a parameter. + REQUIRE(v(1).value() == 2); + } + } + + SECTION("array") + { + auto p = coek::data("p").value(1); + + WHEN("index api") + { + auto v = coek::data_array({4, 4, 4}).name("x").value(1); + REQUIRE(v.size() == 64); + + int ival = 1; + size_t uval = 1; + auto e = p + 1; + // Misc tests to improve code coverage for the collect_args() methods + REQUIRE(v(e, uval, ival).expand().value() == 1); + + REQUIRE(v(uval, uval, e).expand().value() == 1); + + REQUIRE(v(ival, ival, e).expand().value() == 1); + + REQUIRE(v(uval, uval, uval).value() == 1); + + REQUIRE(v(ival, ival, ival).value() == 1); + + REQUIRE_THROWS_WITH(v(uval), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 1 indices."); + + REQUIRE_THROWS_WITH(v(uval, uval), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(e, ival), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(ival, ival), + "Unexpected index value: x is an 3-D data array but is being " + "indexed with 2 indices."); + + REQUIRE_THROWS_WITH(v(100, 100, 100), "Unknown index value: x[100,100,100]"); + } + + WHEN("data value") + { + auto q = coek::data("q").value(1); + auto v = coek::data_array(4).name("x").value(1); + + REQUIRE(v(1).value() == 1); + v.value(q + 1); + REQUIRE(v(1).value() == 2); + q.value(2); + // Changing the value of q does *not* impact the value of v(1), since + // this is data and not a parameter. + REQUIRE(v(1).value() == 2); + } + } +} +#endif + +#if __cpp_lib_variant +TEST_CASE("ND_data_array_errors", "[smoke]") +{ + SECTION("wrong index values") + { + auto p = coek::data("p", {10, 10}).value(1); + REQUIRE_THROWS_WITH(p(11, 11).value(), "Unknown index value: p[11,11]"); + } +} +#endif