-
Notifications
You must be signed in to change notification settings - Fork 8
/
hypergraph.hpp
137 lines (113 loc) · 3.57 KB
/
hypergraph.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once
#include <tuple>
namespace emphf {
template <typename NodeType>
struct hypergraph {
typedef NodeType node_t; // last value is used as sentinel
struct hyperedge {
// deliberately do not initialize, to avoid polluting the
// page cache when initializing large mmapped arrays
hyperedge()
{}
hyperedge(NodeType v0_, NodeType v1_, NodeType v2_)
: v0(v0_)
, v1(v1_)
, v2(v2_)
{}
friend inline
std::ostream& operator<<(std::ostream& os, hyperedge const& t)
{
os << "("
<< t.v0 << ", "
<< t.v1 << ", "
<< t.v2 << ")";
return os;
}
friend inline
bool operator<(hyperedge const& lhs, hyperedge const& rhs)
{
return
std::make_tuple(lhs.v0, lhs.v1, lhs.v2) <
std::make_tuple(rhs.v0, rhs.v1, rhs.v2);
}
friend inline
bool operator==(hyperedge const& lhs, hyperedge const& rhs)
{
return
lhs.v0 == rhs.v0 &&
lhs.v1 == rhs.v1 &&
lhs.v2 == rhs.v2;
}
friend inline
bool operator!=(hyperedge const& lhs, hyperedge const& rhs)
{
return !(lhs == rhs);
}
NodeType v0, v1, v2;
};
static hyperedge sentinel()
{
return hyperedge(-node_t(1), -node_t(1), -node_t(1));
}
struct xored_adj_list {
xored_adj_list(node_t degree_= 0, node_t v1s_ = 0, node_t v2s_ = 0)
: degree(degree_)
, v1s(v1s_)
, v2s(v2s_)
{}
void add_edge(hyperedge const& edge)
{
degree += 1;
xor_edge(edge);
}
void delete_edge(hyperedge const& edge)
{
assert(degree >= 1);
degree -= 1;
xor_edge(edge);
}
hyperedge edge_from(node_t v0) const
{
assert(degree == 1);
return hyperedge(v0, v1s, v2s);
}
node_t degree;
node_t v1s;
node_t v2s;
private:
void xor_edge(hyperedge const& edge)
{
assert(edge.v1 < edge.v2);
v1s ^= edge.v1;
v2s ^= edge.v2;
}
};
};
// a brief note about hyperedge orientations: throughout the
// code we keep the invariant that for every hyperedge (v0,
// v1, v2) it holds v1 < v2. This leaves only three
// orientations, which we index with 0, 1, and 2 depending on
// whether v0 is the first, second, or third smallest node. We
// call the 0-orientation "canonical".
template <typename HyperEdge>
static unsigned orientation(HyperEdge const& t)
{
// although it should be v0 < v1 < v2, sometimes we
// compare sentinel edges
assert(t.v1 <= t.v2);
return (t.v0 > t.v1) + (t.v0 > t.v2);
}
template <typename HyperEdge>
static HyperEdge canonicalize_edge(HyperEdge t)
{
assert(t.v1 <= t.v2);
if (t.v0 > t.v2) {
std::swap(t.v0, t.v2);
}
if (t.v0 > t.v1) {
std::swap(t.v0, t.v1);
}
assert(orientation(t) == 0);
return t;
}
}