Skip to content

Commit

Permalink
decouple cost fn and memorize rank
Browse files Browse the repository at this point in the history
rm CostASI

decouple cost function

connection weight

GOO draft

memorize rank
  • Loading branch information
Goblin80 committed May 5, 2024
1 parent 41b07c0 commit 3158e74
Show file tree
Hide file tree
Showing 14 changed files with 671 additions and 316 deletions.
8 changes: 7 additions & 1 deletion src/engine/joinOrdering/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
add_library(joinOrdering QueryGraph.cpp IKKBZ.cpp RelationBasic.cpp EdgeInfo.cpp CostASI.cpp)
add_library(joinOrdering
QueryGraph.cpp
IKKBZ.cpp
RelationBasic.cpp
EdgeInfo.cpp
CostIKKBZ.cpp
GOO.cpp)
qlever_target_link_libraries(joinOrdering)
85 changes: 0 additions & 85 deletions src/engine/joinOrdering/CostASI.h

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,23 @@
// Author:
// Mahmoud Khalaf (2024-, [email protected])

#include "CostASI.h"
#include "CostIKKBZ.h"

namespace JoinOrdering::ASI {
namespace JoinOrdering {

template <typename N>
requires RelationAble<N>
auto rank(const QueryGraph<N>& g, const N& n) -> float {
auto c = C(g, n);
auto t = T(g, n);

// TODO: what's the rank of root?
if (c == 0) return 0;
auto r = (t - 1) / c;
// assert rank [0, 1]
AD_CONTRACT_CHECK(r >= 0 && r <= 1);
return r;
}

template <typename N>
requires RelationAble<N> auto T(const QueryGraph<N>& g, const N& n) -> float {
// return 0 if Ri is root 113/637
if (g.root == n) return 1;
return g.selectivity.at(n) * static_cast<float>(n.getCardinality());
auto CostIKKBZ<N>::C(const QueryGraph<N>& g, std::span<N> seq) -> float {
if (seq.empty()) return 0.0f;
auto s1 = seq.front();
// auto s2 = seq | std::views::drop(1);
auto s2 = seq.subspan(1);
return C(g, s1) + T(g, s1) * C(g, s2); // TODO: might overflow
}

template <typename N>
requires RelationAble<N> auto C(const QueryGraph<N>& g, const N& n) -> float {
requires RelationAble<N>
auto CostIKKBZ<N>::C(const QueryGraph<N>& g, const N& n) -> float {
// return 0 if Ri is root 113/637
if (g.root == n) return 0;

Expand All @@ -39,15 +29,28 @@ requires RelationAble<N> auto C(const QueryGraph<N>& g, const N& n) -> float {
auto seq = g.hist.at(n);
return C(g, std::span<N>(seq));
}

template <typename N>
requires RelationAble<N>
auto C(const QueryGraph<N>& g, std::span<N> seq) -> float {
if (seq.empty()) return 0.0f;
auto s1 = seq.front();
// auto s2 = seq | std::views::drop(1);
auto s2 = seq.subspan(1);
return C(g, s1) + T(g, s1) * C(g, s2); // TODO: might overflow
auto CostIKKBZ<N>::T(const QueryGraph<N>& g, const N& n) -> float {
// return 0 if Ri is root 113/637
if (g.root == n) return 1;
return g.selectivity.at(n) * static_cast<float>(n.getCardinality());
}
template <typename N>
requires RelationAble<N>
auto CostIKKBZ<N>::rank(const QueryGraph<N>& g, const N& n) -> float {
if (rank_m.contains(n)) return rank_m[n];

} // namespace JoinOrdering::ASI
auto c = C(g, n);
auto t = T(g, n);

// TODO: what's the rank of root?
if (c == 0) return 0;
auto r = (t - 1) / c;
// assert rank [0, 1]
AD_CONTRACT_CHECK(r >= 0 && r <= 1);

rank_m[n] = r;
return r;
}
} // namespace JoinOrdering
65 changes: 65 additions & 0 deletions src/engine/joinOrdering/CostIKKBZ.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author:
// Mahmoud Khalaf (2024-, [email protected])

#pragma once

#include <span>

#include "ICostASI.h"
#include "util/HashMap.h"

namespace JoinOrdering {

template <typename N>
requires RelationAble<N> class CostIKKBZ : public ICostASI<N> {
public:
ad_utility::HashMap<N, float> rank_m;

auto rank(const QueryGraph<N>& g, const N& n) -> float;

/**
*
* calculate T for an uncompound relation s_i * n_i
* (cardinality * selectivity)
*
*
* @param g precedence tree
* @param n Relation
* @return T(n)
*/
auto T(const QueryGraph<N>& g, const N& n) -> float;
/**
*
* a join is called increasing if cost > 1
* a join is called decreasing if cost < 1
*
* ref: 113/637
*
* @param g precedence tree
* @param n Relation
* @return C(n)
*/
auto C(const QueryGraph<N>& g, const N& n) -> float;

/**
*
* calculate cost for a sequence of relations
*
*
* C(eps) = 0
* C(R) = 0 (if R is root)
* C(R) = h_i * (n_i)
* C(S_1 S_2) = C(S1) + T(S1) * C(S2)
*
* ref: 113/637
*
* @param g precedence tree
* @param seq sequence of relations (may include compound relations)
* @return C(S_1 S_2)
*/
auto C(const QueryGraph<N>& g, std::span<N> seq) -> float;
};

} // namespace JoinOrdering
2 changes: 2 additions & 0 deletions src/engine/joinOrdering/EdgeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ namespace JoinOrdering {

EdgeInfo::EdgeInfo() = default;
EdgeInfo::EdgeInfo(Direction dir) : direction(dir) {}

Check warning on line 11 in src/engine/joinOrdering/EdgeInfo.cpp

View check run for this annotation

Codecov / codecov/patch

src/engine/joinOrdering/EdgeInfo.cpp#L11

Added line #L11 was not covered by tests
EdgeInfo::EdgeInfo(Direction dir, float weight)
: direction(dir), weight(weight) {}
} // namespace JoinOrdering
2 changes: 2 additions & 0 deletions src/engine/joinOrdering/EdgeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ class EdgeInfo {
// Ra is a dir of Rb
Direction direction{Direction::UNDIRECTED};
bool hidden{false}; // instead of erasing
float weight{-1};

EdgeInfo();
explicit EdgeInfo(Direction dir);
EdgeInfo(Direction dir, float weight);
};

} // namespace JoinOrdering
66 changes: 66 additions & 0 deletions src/engine/joinOrdering/GOO.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author:
// Mahmoud Khalaf (2024-, [email protected])

#include "GOO.h"

namespace JoinOrdering {

template <typename N>
requires RelationAble<N> auto GOO(QueryGraph<N>& g) -> N {
typedef std::pair<N, N> rr;
auto costfn = [&](const rr& r) {
auto& [a, b] = r;
return g.edges_[a][b].weight * g.cardinality[a] * g.cardinality[b];
};
auto comp = [&](const rr& l, const rr& r) { return costfn(l) < costfn(r); };

// TODO: assert decreasing size
while (true) {
std::vector<rr> zxs = g.iter_pairs();
auto& [a, b] = *std::ranges::min_element(zxs, comp);
auto ab = GOO_combine(g, a, b);
if (zxs.size() == 1) return ab;
// for (auto const& [x, y] : zxs)
// std::cout << x.getLabel() << " " << y.getLabel() << " " <<
// std::fixed
// << costfn(rr(x, y)) << "\n";
}
}

template <typename N>
requires RelationAble<N>
[[maybe_unused]] N GOO_combine(QueryGraph<N>& g, const N& a, const N& b) {
auto w = a.getCardinality() * b.getCardinality() * g.edges_[a][b].weight;
AD_CONTRACT_CHECK(w >= 0);

// add the newly computed cardinality to the
// cardinality map of the query graph.
auto n = N("(" + a.getLabel() + "" + b.getLabel() + ")", w);
g.add_relation(n);

// we keep track of the combined relation in the `hist` map
g.hist[n].push_back(a);
g.hist[n].push_back(b);

// TODO: STL chain iterators
for (auto const& [x, e] : boost::join(g.edges_[a], g.edges_[b])) {
if (e.hidden || x == a || x == b) continue;
g.add_rjoin(n, x, e.weight, Direction::UNDIRECTED);

if (!g.is_common_neighbour(a, b, x)) continue;
// when the 2 relations to be combined have common neighbours
// multiply edge weights of newly combined relation
g.edges_[x][n].weight = g.edges_[a][x].weight * g.edges_[b][x].weight;
g.edges_[n][x].weight = g.edges_[a][x].weight * g.edges_[b][x].weight;
}

// make these relations unreachable
g.rm_relation(a);
g.rm_relation(b);

return n;
}

} // namespace JoinOrdering
42 changes: 42 additions & 0 deletions src/engine/joinOrdering/GOO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2024, University of Freiburg,
// Chair of Algorithms and Data Structures.
// Author:
// Mahmoud Khalaf (2024-, [email protected])

#pragma once

#include <boost/range/join.hpp>

#include "QueryGraph.h"

namespace JoinOrdering {

/**
*
* Greedy Operator Ordering
*
* Repeatedly combine the pair of relations with the minimal cost
* until there is only one left
*
* ref: 101/637
* @param g undirected QueryGraph
* @return bushy join tree
*/
template <typename N>
requires RelationAble<N> auto GOO(QueryGraph<N>& g) -> N;

/**
*
* Remove Relation a and Relation b from the QueryGraph and add a new
* Compound Relation ab with updated weight
*
* @param g undirected QueryGraph
* @param a Relation a
* @param b Relation b
* @return newly created compound relation
*/
template <typename N>
requires RelationAble<N>
[[maybe_unused]] N GOO_combine(QueryGraph<N>& g, const N& a, const N& b);

} // namespace JoinOrdering
Loading

0 comments on commit 3158e74

Please sign in to comment.