Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Framework/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ foreach(t
DeviceMetricsInfo
DeviceSpec
DeviceSpecHelpers
Expressions
ExternalFairMQDeviceProxy
FairMQOptionsRetriever
FairMQResizableBuffer
Expand Down
21 changes: 2 additions & 19 deletions Framework/Core/include/Framework/Expressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
#ifndef O2_FRAMEWORK_EXPRESSIONS_H_
#define O2_FRAMEWORK_EXPRESSIONS_H_

#include "Framework/Kernels.h"

#include <arrow/compute/kernel.h>
#include <variant>
#include <string>
#include <memory>
#include <iosfwd>

namespace o2::framework::expressions
{
Expand Down Expand Up @@ -55,22 +55,6 @@ struct BinaryOpNode {
Op op;
};

struct ArrowDatumSpec {
// datum spec either contains an index, a value of a literal or a binding label
std::variant<std::monostate, size_t, LiteralNode::var_t, std::string> datum;
explicit ArrowDatumSpec(size_t index) : datum{index} {}
explicit ArrowDatumSpec(LiteralNode::var_t literal) : datum{literal} {}
explicit ArrowDatumSpec(std::string binding) : datum{binding} {}
ArrowDatumSpec() : datum{std::monostate{}} {}
};

struct ArrowKernelSpec {
std::unique_ptr<arrow::compute::OpKernel> kernel = nullptr;
ArrowDatumSpec left;
ArrowDatumSpec right;
ArrowDatumSpec result;
};

/// A generic tree node
struct Node {
Node(LiteralNode v) : self{v}, left{nullptr}, right{nullptr}
Expand Down Expand Up @@ -145,7 +129,6 @@ struct Filter {

std::unique_ptr<Node> node;
};

} // namespace o2::framework::expressions

#endif // O2_FRAMEWORK_EXPRESSIONS_H_
39 changes: 39 additions & 0 deletions Framework/Core/src/ExpressionHelpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright CERN and copyright holders of ALICE O2. This software is
// distributed under the terms of the GNU General Public License v3 (GPL
// Version 3), copied verbatim in the file "COPYING".
//
// See http://alice-o2.web.cern.ch/license for full licensing information.
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
#ifndef O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_
#define O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_
#include "Framework/Expressions.h"

namespace o2::framework::expressions
{
struct ArrowDatumSpec {
// datum spec either contains an index, a value of a literal or a binding label
std::variant<std::monostate, size_t, LiteralNode::var_t, std::string> datum;
explicit ArrowDatumSpec(size_t index) : datum{index} {}
explicit ArrowDatumSpec(LiteralNode::var_t literal) : datum{literal} {}
explicit ArrowDatumSpec(std::string binding) : datum{binding} {}
ArrowDatumSpec() : datum{std::monostate{}} {}
};

bool operator==(ArrowDatumSpec const& lhs, ArrowDatumSpec const& rhs);

std::ostream& operator<<(std::ostream& os, ArrowDatumSpec const& spec);

struct ArrowKernelSpec {
std::unique_ptr<arrow::compute::OpKernel> kernel = nullptr;
ArrowDatumSpec left;
ArrowDatumSpec right;
ArrowDatumSpec result;
};

std::vector<ArrowKernelSpec> createKernelsFromFilter(Filter const& filter);
} // namespace o2::framework::expressions

#endif // O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_
88 changes: 52 additions & 36 deletions Framework/Core/src/Expressions.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#include "Framework/Expressions.h"
#include "../src/ExpressionHelpers.h"
#include "Framework/VariantHelpers.h"
#include <stack>

Expand Down Expand Up @@ -53,27 +53,46 @@ struct BinaryOpNodeHelper {
}
};

bool operator==(ArrowDatumSpec const& lhs, ArrowDatumSpec const& rhs)
{
return (lhs.datum == rhs.datum);
}

std::ostream& operator<<(std::ostream& os, ArrowDatumSpec const& spec)
{
std::visit(
overloaded{
[&os](LiteralNode::var_t&& arg) -> void {
std::visit(
[&os](auto&& arg) { os << arg; },
arg);
},
[&os](size_t&& arg) { os << arg; },
[&os](std::string&& arg) { os << arg; },
[](auto&&) {}},
spec.datum);
return os;
}

/// helper struct used to parse trees
struct NodeRecord {
/// pointer to the actual tree node
Node* node_ptr = nullptr;
explicit NodeRecord(Node* node_) : node_ptr(node_) {}
size_t index = 0;
explicit NodeRecord(Node* node_, size_t index_) : node_ptr(node_), index{index_} {}
};

std::vector<ArrowKernelSpec> createKernelsFromFilter(Filter const& filter)
{
std::vector<ArrowDatumSpec> datums;
std::vector<ArrowKernelSpec> kernelSpecs;
std::stack<NodeRecord> path;
auto isLeaf = [](Node const* const node) {
return ((node->left == nullptr) && (node->right == nullptr));
};

size_t index = 0;
// create and put output datum
datums.emplace_back(ArrowDatumSpec{index++});
// insert the top node into stack
path.emplace(filter.node.get());
path.emplace(filter.node.get(), index++);

// while the stack is not empty
while (path.empty() == false) {
Expand All @@ -85,50 +104,47 @@ std::vector<ArrowKernelSpec> createKernelsFromFilter(Filter const& filter)
bool leftLeaf = isLeaf(left);
bool rightLeaf = isLeaf(right);

auto processLeaf = [](Node const* const node) {
return std::visit(
overloaded{
[lh = LiteralNodeHelper{}](LiteralNode node) { return lh(node); },
[bh = BindingNodeHelper{}](BindingNode node) { return bh(node); },
[](auto&&) { return ArrowDatumSpec{}; }},
node->self);
};

// create kernel spec, pop the node and add its children
auto&& kernel =
std::visit(
overloaded{
[bh = BinaryOpNodeHelper{}](BinaryOpNode node) { return bh(node); },
[](auto&&) { return ArrowKernelSpec{}; }},
top.node_ptr->self);
kernel.result = ArrowDatumSpec{top.index};
path.pop();

size_t li = 0;
size_t ri = 0;
size_t ti = index;

auto processLeaf = [&datums](Node const* const node) {
datums.push_back(
std::visit(
overloaded{
[lh = LiteralNodeHelper{}](LiteralNode node) { return lh(node); },
[bh = BindingNodeHelper{}](BindingNode node) { return bh(node); },
[](auto&&) { return ArrowDatumSpec{}; }},
node->self));
};

if (leftLeaf) {
processLeaf(left);
kernel.left = processLeaf(left);
} else {
datums.emplace_back(ArrowDatumSpec{index++});
li = index;
kernel.left = ArrowDatumSpec{index++};
}
li = datums.size() - 1;

if (rightLeaf) {
processLeaf(right);
kernel.right = processLeaf(right);
} else {
datums.emplace_back(ArrowDatumSpec{index++});
ri = index;
kernel.right = ArrowDatumSpec{index++};
}
ri = datums.size() - 1;

// create kernel spec, pop the node and add its children
auto&& kernel =
std::visit(
overloaded{
[bh = BinaryOpNodeHelper{}](BinaryOpNode node) { return bh(node); },
[](auto&&) { return ArrowKernelSpec{}; }},
top.node_ptr->self);
kernel.left = ArrowDatumSpec{li};
kernel.right = ArrowDatumSpec{ri};
kernel.result = ArrowDatumSpec{ti};
kernelSpecs.push_back(std::move(kernel));
path.pop();
if (!leftLeaf)
path.emplace(left);
path.emplace(left, li);
if (!rightLeaf)
path.emplace(right);
path.emplace(right, ri);
}
return kernelSpecs;
}
Expand Down
50 changes: 50 additions & 0 deletions Framework/Core/test/test_Expressions.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright CERN and copyright holders of ALICE O2. This software is
// distributed under the terms of the GNU General Public License v3 (GPL
// Version 3), copied verbatim in the file "COPYING".
//
// See http://alice-o2.web.cern.ch/license for full licensing information.
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#define BOOST_TEST_MODULE Test Framework Expressions
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include "../src/ExpressionHelpers.h"
#include <boost/test/unit_test.hpp>

using namespace o2::framework::expressions;

namespace nodes
{
static BindingNode pt{"pt"};
static BindingNode phi{"phi"};
static BindingNode eta{"eta"};
} // namespace nodes

BOOST_AUTO_TEST_CASE(TestTreeParsing)
{
Filter f = ((nodes::phi > 1) && (nodes::phi < 2)) && (nodes::eta < 1);
auto specs = createKernelsFromFilter(f);
BOOST_REQUIRE_EQUAL(specs[0].left, ArrowDatumSpec{1u});
BOOST_REQUIRE_EQUAL(specs[0].right, ArrowDatumSpec{2u});
BOOST_REQUIRE_EQUAL(specs[0].result, ArrowDatumSpec{0u});

BOOST_REQUIRE_EQUAL(specs[1].left, ArrowDatumSpec{std::string{"eta"}});
BOOST_REQUIRE_EQUAL(specs[1].right, ArrowDatumSpec{LiteralNode::var_t{1}});
BOOST_REQUIRE_EQUAL(specs[1].result, ArrowDatumSpec{2u});

BOOST_REQUIRE_EQUAL(specs[2].left, ArrowDatumSpec{3u});
BOOST_REQUIRE_EQUAL(specs[2].right, ArrowDatumSpec{4u});
BOOST_REQUIRE_EQUAL(specs[2].result, ArrowDatumSpec{1u});

BOOST_REQUIRE_EQUAL(specs[3].left, ArrowDatumSpec{std::string{"phi"}});
BOOST_REQUIRE_EQUAL(specs[3].right, ArrowDatumSpec{LiteralNode::var_t{2}});
BOOST_REQUIRE_EQUAL(specs[3].result, ArrowDatumSpec{4u});

BOOST_REQUIRE_EQUAL(specs[4].left, ArrowDatumSpec{std::string{"phi"}});
BOOST_REQUIRE_EQUAL(specs[4].right, ArrowDatumSpec{LiteralNode::var_t{1}});
BOOST_REQUIRE_EQUAL(specs[4].result, ArrowDatumSpec{3u});
}