Skip to content

Commit

Permalink
Refactor SPARQL expression definitions + add ABS, CEIL, FLOOR, ROUND (#…
Browse files Browse the repository at this point in the history
…1043)

1. Refactor the code for the various SPARQL expressions and functions. The definitions are now in `.cpp` files, which reduces compile time. Each expression is defined in three parts: the actual behavior (e.g., `extractYear`), the corresponding type (e.g., `YearExpression` defined via the macro `NARY_EXPRESSION`), and the corresponding factory function that is used in the SPARQL parser (e.g., `makeYearExpression`).

2. Add the following four unary functions: `ABS`, `CEIL`, `FLOOR`, `ROUND`. Pay attention to the detail that according to the SPARQL standard, `ROUND` of negative numbers that lie exactly between two integers (e.g., `-42.5`) rounds towards zero (`-42`), unlike `std::round`, which rounds away from zero (`-43`).
  • Loading branch information
joka921 authored Jul 27, 2023
1 parent f059723 commit d50499f
Show file tree
Hide file tree
Showing 18 changed files with 881 additions and 548 deletions.
10 changes: 6 additions & 4 deletions .github/workflows/code-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ jobs:
with:
submodules: "recursive"

- name: Install dependencies
run: |
sudo gem install apt-spy2 && sudo apt-spy2 fix --commit --launchpad --country=US
sudo apt-get update
- name: Install clang 16
# The sed command fixes a bug in `llvm.sh` in combination with the latest version of
# `apt-key`. Without it the GPG key for the llvm repository is downloaded but deleted
Expand All @@ -49,8 +53,6 @@ jobs:
wget https://apt.llvm.org/llvm.sh
sudo chmod +x llvm.sh
sed 's/apt-key del/echo/' llvm.sh -iy
sudo ./llvm.sh 15
sudo apt install clang-15 llvm-15
sudo ./llvm.sh 16 all
- name: Install dependencies
run: |
Expand Down Expand Up @@ -89,8 +91,8 @@ jobs:
- name: Process coverage info
working-directory: ${{github.workspace}}/build/test
run: >
llvm-profdata-15 merge -sparse *.profraw -o default.profdata;
xargs -a tests.txt llvm-cov-15 export --dump --format=lcov --instr-profile ./default.profdata --ignore-filename-regex="/third_party/" --ignore-filename-regex="/generated/" --ignore-filename-regex="/nlohmann/" --ignore-filename-regex="/ctre/" --ignore-filename-regex="/test/" --ignore-filename-regex="/benchmark/" > ./coverage.lcov
llvm-profdata-16 merge -sparse *.profraw -o default.profdata;
xargs -a tests.txt llvm-cov-16 export --dump --format=lcov --instr-profile ./default.profdata --ignore-filename-regex="/third_party/" --ignore-filename-regex="/generated/" --ignore-filename-regex="/nlohmann/" --ignore-filename-regex="/ctre/" --ignore-filename-regex="/test/" --ignore-filename-regex="/benchmark/" > ./coverage.lcov
# Only upload the coverage directly if this is not a pull request. In this
# case we are on the master branch and have access to the Codecov token.
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/format-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
- uses: actions/checkout@v3
- name: Install dependencies
run: |
# The following line currently seems to be necessary to work around a bug in the installation.
sudo apt remove python3-lldb-*
wget https://apt.llvm.org/llvm.sh
sudo chmod +x llvm.sh
sed 's/apt-key del/echo/' llvm.sh -iy
Expand Down
18 changes: 6 additions & 12 deletions src/engine/sparqlExpressions/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
add_library(sparqlExpressions
SparqlExpressionTypes.h
SparqlExpression.h
AggregateExpression.h
GroupConcatExpression.h
SparqlExpressionGenerators.h
SparqlExpressionValueGetters.h SparqlExpressionValueGetters.cpp
NaryExpression.h NaryExpression.cpp
SetOfIntervals.h SetOfIntervals.cpp
LiteralExpression.h GroupConcatExpression.h
SparqlExpressionPimpl.h SparqlExpressionPimpl.cpp
SampleExpression.h SampleExpression.cpp
SparqlExpressionValueGetters.cpp
NaryExpression.cpp
SetOfIntervals.cpp
SparqlExpressionPimpl.cpp
SampleExpression.cpp
RelationalExpressions.cpp AggregateExpression.cpp RegexExpression.cpp
LangExpression.cpp)
LangExpression.cpp NumericUnaryExpressions.cpp NumericBinaryExpressions.cpp DateExpressions.cpp StringExpressions.cpp)

qlever_target_link_libraries(sparqlExpressions index)
60 changes: 60 additions & 0 deletions src/engine/sparqlExpressions/DateExpressions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2023, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author: Johannes Kalmbach <[email protected]>

#include "engine/sparqlExpressions/NaryExpressionImpl.h"

namespace sparqlExpression {
namespace detail {
// Date functions.
// The input is `std::nullopt` if the argument to the expression is not a date.
inline auto extractYear = [](std::optional<DateOrLargeYear> d) {
if (!d.has_value()) {
return Id::makeUndefined();
} else {
return Id::makeFromInt(d->getYear());
}
};

inline auto extractMonth = [](std::optional<DateOrLargeYear> d) {
// TODO<C++23> Use the monadic operations for std::optional
if (!d.has_value()) {
return Id::makeUndefined();
}
auto optionalMonth = d.value().getMonth();
if (!optionalMonth.has_value()) {
return Id::makeUndefined();
}
return Id::makeFromInt(optionalMonth.value());
};

inline auto extractDay = [](std::optional<DateOrLargeYear> d) {
// TODO<C++23> Use the monadic operations for `std::optional`.
if (!d.has_value()) {
return Id::makeUndefined();
}
auto optionalDay = d.value().getDay();
if (!optionalDay.has_value()) {
return Id::makeUndefined();
}
return Id::makeFromInt(optionalDay.value());
};

NARY_EXPRESSION(YearExpression, 1, FV<decltype(extractYear), DateValueGetter>);
NARY_EXPRESSION(MonthExpression, 1,
FV<decltype(extractMonth), DateValueGetter>);
NARY_EXPRESSION(DayExpression, 1, FV<decltype(extractDay), DateValueGetter>);
} // namespace detail
using namespace detail;
SparqlExpression::Ptr makeYearExpression(SparqlExpression::Ptr child) {
return std::make_unique<YearExpression>(std::move(child));
}

SparqlExpression::Ptr makeDayExpression(SparqlExpression::Ptr child) {
return std::make_unique<DayExpression>(std::move(child));
}

SparqlExpression::Ptr makeMonthExpression(SparqlExpression::Ptr child) {
return std::make_unique<MonthExpression>(std::move(child));
}
} // namespace sparqlExpression
95 changes: 21 additions & 74 deletions src/engine/sparqlExpressions/NaryExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,87 +4,34 @@

#include "engine/sparqlExpressions/NaryExpression.h"

#include "engine/sparqlExpressions/NaryExpressionImpl.h"
#include "util/GeoSparqlHelpers.h"

namespace sparqlExpression {
namespace detail {
NARY_EXPRESSION(LongitudeExpression, 1,
FV<NumericIdWrapper<decltype(ad_utility::wktLongitude), true>,
StringValueGetter>);
NARY_EXPRESSION(LatitudeExpression, 1,
FV<NumericIdWrapper<decltype(ad_utility::wktLatitude), true>,
StringValueGetter>);
NARY_EXPRESSION(DistExpression, 2,
FV<NumericIdWrapper<decltype(ad_utility::wktDist), true>,
StringValueGetter>);

// _____________________________________________________________________________
template <typename Op>
requires(isOperation<Op>)
NaryExpression<Op>::NaryExpression(Children&& children)
: _children{std::move(children)} {}

// _____________________________________________________________________________

template <typename NaryOperation>
requires(isOperation<NaryOperation>)
ExpressionResult NaryExpression<NaryOperation>::evaluate(
EvaluationContext* context) const {
auto resultsOfChildren = ad_utility::applyFunctionToEachElementOfTuple(
[context](const auto& child) { return child->evaluate(context); },
_children);

// A function that only takes several `ExpressionResult`s,
// and evaluates the expression.
auto evaluateOnChildrenResults =
std::bind_front(ad_utility::visitWithVariantsAndParameters,
evaluateOnChildrenOperands, NaryOperation{}, context);
} // namespace detail

return std::apply(evaluateOnChildrenResults, std::move(resultsOfChildren));
using namespace detail;
SparqlExpression::Ptr makeDistExpression(SparqlExpression::Ptr child1,
SparqlExpression::Ptr child2) {
return std::make_unique<DistExpression>(std::move(child1), std::move(child2));
}

// _____________________________________________________________________________
template <typename Op>
requires(isOperation<Op>)
std::span<SparqlExpression::Ptr> NaryExpression<Op>::children() {
return {_children.data(), _children.size()};
SparqlExpression::Ptr makeLatitudeExpression(SparqlExpression::Ptr child) {
return std::make_unique<LatitudeExpression>(std::move(child));
}

// __________________________________________________________________________
template <typename Op>
requires(isOperation<Op>) [[nodiscard]] string NaryExpression<Op>::getCacheKey(
const VariableToColumnMap& varColMap) const {
string key = typeid(*this).name();
for (const auto& child : _children) {
key += child->getCacheKey(varColMap);
}
return key;
SparqlExpression::Ptr makeLongitudeExpression(SparqlExpression::Ptr child) {
return std::make_unique<LongitudeExpression>(std::move(child));
}

#define INSTANTIATE_NARY(N, X, ...) \
template class NaryExpression<Operation<N, X, __VA_ARGS__>>

INSTANTIATE_NARY(2, FV<decltype(orLambda), EffectiveBooleanValueGetter>,
SET<SetOfIntervals::Union>);

INSTANTIATE_NARY(2, FV<decltype(andLambda), EffectiveBooleanValueGetter>,
SET<SetOfIntervals::Intersection>);

INSTANTIATE_NARY(1, FV<decltype(unaryNegate), EffectiveBooleanValueGetter>,
SET<SetOfIntervals::Complement>);

INSTANTIATE_NARY(1, FV<decltype(unaryMinus), NumericValueGetter>);

INSTANTIATE_NARY(2, FV<decltype(multiply), NumericValueGetter>);

INSTANTIATE_NARY(2, FV<decltype(divide), NumericValueGetter>);

INSTANTIATE_NARY(2, FV<decltype(add), NumericValueGetter>);

INSTANTIATE_NARY(2, FV<decltype(subtract), NumericValueGetter>);

INSTANTIATE_NARY(1,
FV<NumericIdWrapper<decltype(ad_utility::wktLongitude), true>,
StringValueGetter>);
INSTANTIATE_NARY(1,
FV<NumericIdWrapper<decltype(ad_utility::wktLatitude), true>,
StringValueGetter>);
INSTANTIATE_NARY(2, FV<NumericIdWrapper<decltype(ad_utility::wktDist), true>,
StringValueGetter>);

INSTANTIATE_NARY(1, FV<decltype(extractYear), DateValueGetter>);
INSTANTIATE_NARY(1, FV<decltype(extractMonth), DateValueGetter>);
INSTANTIATE_NARY(1, FV<decltype(extractDay), DateValueGetter>);
INSTANTIATE_NARY(1, FV<std::identity, StringValueGetter>);
INSTANTIATE_NARY(1, FV<decltype(strlen), StringValueGetter>);
} // namespace detail
} // namespace sparqlExpression
Loading

0 comments on commit d50499f

Please sign in to comment.