From 2c98418e80a72f0905e1d678864805839eeff09c Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 28 Oct 2024 22:24:35 +0100
Subject: [PATCH] Add parsing of R^d and R^dxd tuple arguments which were
 missing

Also add corresponding unit tests
---
 ...STNodeBuiltinFunctionExpressionBuilder.cpp |  39 +++-
 ...STNodeBuiltinFunctionExpressionBuilder.cpp | 104 +++++++++-
 tests/test_BuiltinFunctionEmbedder.cpp        | 194 ++++++++++++++++++
 tests/test_BuiltinFunctionRegister.hpp        |  27 +++
 4 files changed, 362 insertions(+), 2 deletions(-)

diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 169540df2..1a1e23785 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -204,6 +204,43 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       case ASTNodeDataType::double_t: {
         return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, double>>(argument_number);
       }
+      case ASTNodeDataType::vector_t: {
+        switch (tuple_content_type.dimension()) {
+        case 1: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<1>>>(argument_number);
+        }
+        case 2: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<2>>>(argument_number);
+        }
+        case 3: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyVector<3>>>(argument_number);
+        }
+          // LCOV_EXCL_START
+        default: {
+          throw UnexpectedError(dataTypeName(tuple_content_type) + " unexpected dimension of vector");
+        }
+          // LCOV_EXCL_STOP
+        }
+      }
+      case ASTNodeDataType::matrix_t: {
+        Assert(tuple_content_type.numberOfRows() == tuple_content_type.numberOfColumns());
+        switch (tuple_content_type.numberOfRows()) {
+        case 1: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyMatrix<1>>>(argument_number);
+        }
+        case 2: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyMatrix<2>>>(argument_number);
+        }
+        case 3: {
+          return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, TinyMatrix<3>>>(argument_number);
+        }
+          // LCOV_EXCL_START
+        default: {
+          throw UnexpectedError(dataTypeName(tuple_content_type) + " unexpected dimension of matrix");
+        }
+          // LCOV_EXCL_STOP
+        }
+      }
       case ASTNodeDataType::string_t: {
         return std::make_unique<FunctionTupleArgumentConverter<ParameterContentT, std::string>>(argument_number);
       }
@@ -281,7 +318,7 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
       }
         // LCOV_EXCL_START
       default: {
-        throw UnexpectedError(dataTypeName(arg_data_type) + " unexpected dimension of vector");
+        throw UnexpectedError(dataTypeName(arg_data_type) + " unexpected dimension of matrix");
       }
         // LCOV_EXCL_STOP
       }
diff --git a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 05b64ce51..09b2a05f2 100644
--- a/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/tests/test_ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -1201,7 +1201,7 @@ tuple_RtoB(1.2);
       CHECK_AST(data, result);
     }
 
-    SECTION("tuple(R) -> tuple(R)")
+    SECTION("tuple(R) -> B")
     {
       std::string_view data = R"(
 let t:(R), t = (1,2,4,6);
@@ -1218,6 +1218,108 @@ tuple_RtoB(t);
       CHECK_AST(data, result);
     }
 
+    SECTION("tuple(R^1) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^1), t = ([1],[2],[4]);
+tuple_R1toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R1toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(R^2) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^2), t = ([1,1],[2,2],[4,3]);
+tuple_R2toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R2toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(R^3) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^3), t = ([1,1,2],[2,3,2],[4,3.2,2]);
+tuple_R3toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R3toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(R^1x1) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^1x1), t = ([[1]],[[2]],[[4]]);
+tuple_R11toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R11toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(R^2x2) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^2x2), t = ([[1,2],[3,4]],[[2,4],[1,3]]);
+tuple_R22toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R22toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
+    SECTION("tuple(R^3x3) -> B")
+    {
+      std::string_view data = R"(
+let t:(R^3x3), t = ([[1,2,3],[5,6,7],[8,9,10]],[[2,4,8],[1,3,2],[3,1,6]]);
+tuple_R33toB(t);
+)";
+
+      std::string_view result = R"(
+(root:ASTNodeListProcessor)
+ `-(language::function_evaluation:BuiltinFunctionProcessor)
+     +-(language::name:tuple_R33toB:FakeProcessor)
+     `-(language::name:t:NameProcessor)
+)";
+
+      CHECK_AST(data, result);
+    }
+
     SECTION("list -> tuple(R)")
     {
       std::string_view data = R"(
diff --git a/tests/test_BuiltinFunctionEmbedder.cpp b/tests/test_BuiltinFunctionEmbedder.cpp
index be28e7d75..62c5129cd 100644
--- a/tests/test_BuiltinFunctionEmbedder.cpp
+++ b/tests/test_BuiltinFunctionEmbedder.cpp
@@ -231,6 +231,200 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]")
                           demangle<std::vector<EmbeddedData>>() + "\" to \"" + demangle<std::vector<uint64_t>>() + '"');
   }
 
+  SECTION("int64_t(std::vector<int64_t>) BuiltinFunctionEmbedder")
+  {
+    std::function sum = [&](const std::vector<int64_t>& x) -> int64_t {
+      int64_t s = 0;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<int64_t(const std::vector<int64_t>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::int_t);
+
+    REQUIRE(std::get<int64_t>(i_embedded_c->apply({std::vector{1l, -2l, 3l}})) == 2);
+    REQUIRE(std::get<int64_t>(i_embedded_c->apply({std::vector{-1l, -2l, 3l, 4l}})) == 4);
+
+    REQUIRE_THROWS_WITH(i_embedded_c->apply({std::vector{1.2, 2.3, 3.1, 4.4}}),
+                        "unexpected error: unexpected argument types while casting \"" +
+                          demangle<std::vector<double>>() + "\" to \"" + demangle<std::vector<int64_t>>() + '"');
+
+    REQUIRE_THROWS_WITH(i_embedded_c->apply({std::vector<EmbeddedData>{}}),
+                        "unexpected error: unexpected argument types while casting \"" +
+                          demangle<std::vector<EmbeddedData>>() + "\" to \"" + demangle<std::vector<int64_t>>() + '"');
+  }
+
+  SECTION("double(std::vector<double>) BuiltinFunctionEmbedder")
+  {
+    std::function sum = [&](const std::vector<double>& x) -> double {
+      double s = 0;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<double(const std::vector<double>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::double_t);
+
+    REQUIRE(std::get<double>(i_embedded_c->apply({std::vector<double>{1.2, -2.2, 3.1}})) == 1.2 - 2.2 + 3.1);
+  }
+
+  SECTION("TinyVector<1>(std::vector<TinyVector<1>>) BuiltinFunctionEmbedder")
+  {
+    using Rd          = TinyVector<1>;
+    std::function sum = [&](const std::vector<Rd>& x) -> Rd {
+      Rd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rd(const std::vector<Rd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rd>);
+
+    REQUIRE(std::get<Rd>(i_embedded_c->apply({std::vector<Rd>{Rd{1.2}, Rd{-2.2}, Rd{3.1}}})) ==
+            Rd{1.2} - Rd{2.2} + Rd{3.1});
+  }
+
+  SECTION("TinyVector<2>(std::vector<TinyVector<2>>) BuiltinFunctionEmbedder")
+  {
+    using Rd          = TinyVector<2>;
+    std::function sum = [&](const std::vector<Rd>& x) -> Rd {
+      Rd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rd(const std::vector<Rd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rd>);
+
+    REQUIRE(std::get<Rd>(i_embedded_c->apply({std::vector<Rd>{Rd{1.2, 1}, Rd{-2.2, 0.7}, Rd{3.1, 1.2}}})) ==
+            Rd{1.2, 1} + Rd{-2.2, 0.7} + Rd{3.1, 1.2});
+  }
+
+  SECTION("TinyVector<3>(std::vector<TinyVector<3>>) BuiltinFunctionEmbedder")
+  {
+    using Rd          = TinyVector<3>;
+    std::function sum = [&](const std::vector<Rd>& x) -> Rd {
+      Rd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rd(const std::vector<Rd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rd>);
+
+    REQUIRE(
+      std::get<Rd>(i_embedded_c->apply({std::vector<Rd>{Rd{1.2, 1, -2}, Rd{-2.2, 0.7, 0.6}, Rd{3.1, 1.2, 2.1}}})) ==
+      Rd{1.2, 1, -2} + Rd{-2.2, 0.7, 0.6} + Rd{3.1, 1.2, 2.1});
+  }
+
+  SECTION("TinyMatrix<1>(std::vector<TinyMatrix<1>>) BuiltinFunctionEmbedder")
+  {
+    using Rdxd        = TinyMatrix<1>;
+    std::function sum = [&](const std::vector<Rdxd>& x) -> Rdxd {
+      Rdxd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rdxd(const std::vector<Rdxd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rdxd>);
+
+    REQUIRE(std::get<Rdxd>(i_embedded_c->apply({std::vector<Rdxd>{Rdxd{1.2}, Rdxd{-2.2}, Rdxd{3.1}}})) ==
+            Rdxd{1.2} - Rdxd{2.2} + Rdxd{3.1});
+  }
+
+  SECTION("TinyMatrix<2>(std::vector<TinyMatrix<2>>) BuiltinFunctionEmbedder")
+  {
+    using Rdxd        = TinyMatrix<2>;
+    std::function sum = [&](const std::vector<Rdxd>& x) -> Rdxd {
+      Rdxd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rdxd(const std::vector<Rdxd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rdxd>);
+
+    REQUIRE(std::get<Rdxd>(i_embedded_c->apply(
+              {std::vector<Rdxd>{Rdxd{1.2, 1, -1, 3}, Rdxd{-2.2, 3, -2, 6}, Rdxd{3.1, 2, -1, 3}}})) ==
+            Rdxd{1.2, 1, -1, 3} + Rdxd{-2.2, 3, -2, 6} + Rdxd{3.1, 2, -1, 3});
+  }
+
+  SECTION("TinyMatrix<3>(std::vector<TinyMatrix<3>>) BuiltinFunctionEmbedder")
+  {
+    using Rdxd        = TinyMatrix<3>;
+    std::function sum = [&](const std::vector<Rdxd>& x) -> Rdxd {
+      Rdxd s = zero;
+      for (size_t i = 0; i < x.size(); ++i) {
+        s += x[i];
+      }
+      return s;
+    };
+
+    std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c =
+      std::make_unique<BuiltinFunctionEmbedder<Rdxd(const std::vector<Rdxd>&)>>(sum);
+
+    REQUIRE(i_embedded_c->numberOfParameters() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1);
+    REQUIRE(i_embedded_c->getParameterDataTypes()[0] == ASTNodeDataType::tuple_t);
+    REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<Rdxd>);
+
+    REQUIRE(std::get<Rdxd>(i_embedded_c->apply(
+              {std::vector<Rdxd>{Rdxd{1.2, 1, -1, 3, 1, 2, 5, 6, -3}, Rdxd{-2.2, 3, -2, 6, 1.2, 2, 1.3, -6, 7},
+                                 Rdxd{3.1, 2, -1, 3, 2, 3.2, 2, 6, -7}}})) ==
+            Rdxd{1.2, 1, -1, 3, 1, 2, 5, 6, -3} + Rdxd{-2.2, 3, -2, 6, 1.2, 2, 1.3, -6, 7} +
+              Rdxd{3.1, 2, -1, 3, 2, 3.2, 2, 6, -7});
+  }
+
   SECTION("uint64_t(std::vector<EmbeddedData>) BuiltinFunctionEmbedder")
   {
     std::function sum = [&](const std::vector<std::shared_ptr<const uint64_t>>& x) -> uint64_t {
diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp
index dfc7da319..f763301a1 100644
--- a/tests/test_BuiltinFunctionRegister.hpp
+++ b/tests/test_BuiltinFunctionRegister.hpp
@@ -137,6 +137,33 @@ class test_BuiltinFunctionRegister
       std::make_pair("tuple_RtoB:(R)", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<double>)>>(
                                          [](const std::vector<double>&) -> bool { return false; })));
 
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R1toB:(R^1)", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyVector<1>>)>>(
+                                            [](const std::vector<TinyVector<1>>&) -> bool { return false; })));
+
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R2toB:(R^2)", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyVector<2>>)>>(
+                                            [](const std::vector<TinyVector<2>>&) -> bool { return false; })));
+
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R3toB:(R^3)", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyVector<3>>)>>(
+                                            [](const std::vector<TinyVector<3>>&) -> bool { return false; })));
+
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R11toB:(R^1x1)",
+                     std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyMatrix<1>>)>>(
+                       [](const std::vector<TinyMatrix<1>>&) -> bool { return false; })));
+
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R22toB:(R^2x2)",
+                     std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyMatrix<2>>)>>(
+                       [](const std::vector<TinyMatrix<2>>&) -> bool { return false; })));
+
+    m_name_builtin_function_map.insert(
+      std::make_pair("tuple_R33toB:(R^3x3)",
+                     std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<TinyMatrix<3>>)>>(
+                       [](const std::vector<TinyMatrix<3>>&) -> bool { return false; })));
+
     m_name_builtin_function_map.insert(
       std::make_pair("tuple_stringtoB:(string)",
                      std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<std::string>)>>(
-- 
GitLab