From 414f50c39f2d9cc17e2404f8a14a0ba8eb779e41 Mon Sep 17 00:00:00 2001 From: "c.u." Date: Sun, 13 Oct 2024 14:26:10 +0200 Subject: [PATCH] Implement `math:pow()` (#1549) Many functions from , like `sqrt`, `sin`, `cos`, ... are already implemented in Qlever, but not `pow`. This PR implements `math:pow(base, exp)`. --- src/engine/sparqlExpressions/NaryExpression.h | 2 ++ .../NumericBinaryExpressions.cpp | 13 +++++++++++++ .../sparqlParser/SparqlQleverVisitor.cpp | 5 +++++ test/SparqlAntlrParserTest.cpp | 18 +++++++++++------- test/SparqlExpressionTest.cpp | 3 +++ 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/engine/sparqlExpressions/NaryExpression.h b/src/engine/sparqlExpressions/NaryExpression.h index 9c24fbb865..5237a2283a 100644 --- a/src/engine/sparqlExpressions/NaryExpression.h +++ b/src/engine/sparqlExpressions/NaryExpression.h @@ -42,6 +42,8 @@ SparqlExpression::Ptr makeSqrtExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeSinExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeCosExpression(SparqlExpression::Ptr child); SparqlExpression::Ptr makeTanExpression(SparqlExpression::Ptr child); +SparqlExpression::Ptr makePowExpression(SparqlExpression::Ptr child1, + SparqlExpression::Ptr child2); SparqlExpression::Ptr makeDistExpression(SparqlExpression::Ptr child1, SparqlExpression::Ptr child2); diff --git a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp index fca4da662d..e5852a6add 100644 --- a/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp +++ b/src/engine/sparqlExpressions/NumericBinaryExpressions.cpp @@ -2,6 +2,7 @@ // Chair of Algorithms and Data Structures. // Author: Johannes Kalmbach #include "engine/sparqlExpressions/NaryExpressionImpl.h" +#include "engine/sparqlExpressions/SparqlExpressionValueGetters.h" namespace sparqlExpression { namespace detail { @@ -33,6 +34,13 @@ inline auto subtract = makeNumericExpression>(); NARY_EXPRESSION(SubtractExpression, 2, FV); +// Power. +inline auto powImpl = [](double base, double exp) { + return std::pow(base, exp); +}; +inline auto pow = makeNumericExpression(); +NARY_EXPRESSION(PowExpression, 2, FV); + // Or inline auto orLambda = [](TernaryBool a, TernaryBool b) { using enum TernaryBool; @@ -96,4 +104,9 @@ SparqlExpression::Ptr makeOrExpression(SparqlExpression::Ptr child1, SparqlExpression::Ptr child2) { return std::make_unique(std::move(child1), std::move(child2)); } + +SparqlExpression::Ptr makePowExpression(SparqlExpression::Ptr child1, + SparqlExpression::Ptr child2) { + return std::make_unique(std::move(child1), std::move(child2)); +} } // namespace sparqlExpression diff --git a/src/parser/sparqlParser/SparqlQleverVisitor.cpp b/src/parser/sparqlParser/SparqlQleverVisitor.cpp index 84a9d57f94..777f29714d 100644 --- a/src/parser/sparqlParser/SparqlQleverVisitor.cpp +++ b/src/parser/sparqlParser/SparqlQleverVisitor.cpp @@ -17,6 +17,7 @@ #include "engine/sparqlExpressions/CountStarExpression.h" #include "engine/sparqlExpressions/GroupConcatExpression.h" #include "engine/sparqlExpressions/LiteralExpression.h" +#include "engine/sparqlExpressions/NaryExpression.h" #include "engine/sparqlExpressions/NowDatetimeExpression.h" #include "engine/sparqlExpressions/RandomExpression.h" #include "engine/sparqlExpressions/RegexExpression.h" @@ -131,6 +132,10 @@ ExpressionPtr Visitor::processIriFunctionCall( } else if (functionName == "tan") { checkNumArgs(1); return sparqlExpression::makeTanExpression(std::move(argList[0])); + } else if (functionName == "pow") { + checkNumArgs(2); + return sparqlExpression::makePowExpression(std::move(argList[0]), + std::move(argList[1])); } } else if (checkPrefix(XSD_PREFIX)) { if (functionName == "integer" || functionName == "int") { diff --git a/test/SparqlAntlrParserTest.cpp b/test/SparqlAntlrParserTest.cpp index 24f52c73a8..0ee1705f46 100644 --- a/test/SparqlAntlrParserTest.cpp +++ b/test/SparqlAntlrParserTest.cpp @@ -19,6 +19,7 @@ #include "engine/sparqlExpressions/CountStarExpression.h" #include "engine/sparqlExpressions/GroupConcatExpression.h" #include "engine/sparqlExpressions/LiteralExpression.h" +#include "engine/sparqlExpressions/NaryExpression.h" #include "engine/sparqlExpressions/NowDatetimeExpression.h" #include "engine/sparqlExpressions/RandomExpression.h" #include "engine/sparqlExpressions/RegexExpression.h" @@ -1669,6 +1670,9 @@ TEST(SparqlParser, FunctionCall) { matchUnary(&makeCosExpression)); expectFunctionCall(absl::StrCat(math, "tan>(?x)"), matchUnary(&makeTanExpression)); + expectFunctionCall( + absl::StrCat(math, "pow>(?a, ?b)"), + matchNary(&makePowExpression, Variable{"?a"}, Variable{"?b"})); expectFunctionCall(absl::StrCat(xsd, "int>(?x)"), matchUnary(&makeConvertToIntExpression)); expectFunctionCall(absl::StrCat(xsd, "integer>(?x)"), @@ -1679,14 +1683,14 @@ TEST(SparqlParser, FunctionCall) { matchUnary(&makeConvertToDoubleExpression)); // Wrong number of arguments. - expectFunctionCallFails( - "(?a)"); - // Unknown function with the `geof:` prefix. - expectFunctionCallFails( - "()"); + expectFunctionCallFails(absl::StrCat(geof, "distance>(?a)")); + // Unknown function with `geof:`, `math:`, or `xsd:` prefix. + expectFunctionCallFails(absl::StrCat(geof, "nada>(?x)")); + expectFunctionCallFails(absl::StrCat(math, "nada>(?x)")); + expectFunctionCallFails(absl::StrCat(xsd, "nada>(?x)")); // Prefix for which no function is known. - expectFunctionCallFails( - "()"); + std::string prefixNexistepas = ""; + expectFunctionCallFails(absl::StrCat(prefixNexistepas, "nada>(?x)")); } // ______________________________________________________________________________ diff --git a/test/SparqlExpressionTest.cpp b/test/SparqlExpressionTest.cpp index 4142ed9d41..ab5b3add68 100644 --- a/test/SparqlExpressionTest.cpp +++ b/test/SparqlExpressionTest.cpp @@ -910,6 +910,9 @@ TEST(SparqlExpression, customNumericFunctions) { testUnaryExpression( std::vector{I(0), D(1), D(2), D(-1)}, std::vector{D(0), D(tan(1)), D(tan(2)), D(tan(-1))}); + auto checkPow = std::bind_front(testNaryExpression, &makePowExpression); + checkPow(Ids{D(1), D(32), U, U}, Ids{I(5), D(2), U, D(0)}, + IdOrLiteralOrIriVec{I(0), D(5), I(0), lit("abc")}); } // ____________________________________________________________________________