Skip to content

Commit 0c41df7

Browse files
suncanghuaisuncanghuai
andauthored
introduce WeightBalancedLibra algorithm(vertex-cut graph partition) (#249)
* implement WeightBalancedLibra algorithm based on paper pseudocode * add weight-related apis for class CoordinatedPartitionState * adjust set operations of class CoordinatedRecord * append a testcase in PartitionTest.cpp for WB-Libra Co-authored-by: suncanghuai <[email protected]>
1 parent dace792 commit 0c41df7

File tree

10 files changed

+400
-16
lines changed

10 files changed

+400
-16
lines changed

include/Graph/Graph.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2486,10 +2486,10 @@ namespace CXXGRAPH
24862486
}
24872487

24882488
template <typename T>
2489-
PartitionMap<T> Graph<T>::partitionGraph(PARTITIONING::PartitionAlgorithm algorithm, unsigned int numberOfPartitions, double param1, double param2, double param3, unsigned int numberOfthreads) const
2489+
PartitionMap<T> Graph<T>::partitionGraph(PARTITIONING::PartitionAlgorithm algorithm, unsigned int numberOfPartitions, double param1, double param2, double param3, unsigned int numberOfThreads) const
24902490
{
24912491
PartitionMap<T> partitionMap;
2492-
PARTITIONING::Globals globals(numberOfPartitions, algorithm, param1, param2, param3, numberOfthreads);
2492+
PARTITIONING::Globals globals(numberOfPartitions, algorithm, param1, param2, param3, numberOfThreads);
24932493
const T_EdgeSet<T> & edgeSet = getEdgeSet();
24942494
globals.edgeCardinality = edgeSet.size();
24952495
globals.vertexCardinality = this->getNodeSet().size();

include/Partitioning/CoordinatedPartitionState.hpp

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,14 @@ namespace CXXGRAPH
4242
private:
4343
std::map<int, std::shared_ptr<CoordinatedRecord<T>>> record_map;
4444
std::vector<int> machines_load_edges;
45+
std::vector<double> machines_weight_edges;
4546
std::vector<int> machines_load_vertices;
4647
PartitionMap<T> partition_map;
4748
Globals GLOBALS;
4849
int MAX_LOAD;
4950
std::shared_ptr<std::mutex> machines_load_edges_mutex = nullptr;
5051
std::shared_ptr<std::mutex> machines_load_vertices_mutex = nullptr;
52+
std::shared_ptr<std::mutex> machines_weight_edges_mutex = nullptr;
5153
std::shared_ptr<std::mutex> record_map_mutex = nullptr;
5254
//DatWriter out; //to print the final partition of each edge
5355
public:
@@ -56,10 +58,14 @@ namespace CXXGRAPH
5658

5759
std::shared_ptr<Record<T>> getRecord(int x);
5860
int getMachineLoad(int m);
61+
int getMachineWeight(int m);
5962
int getMachineLoadVertices(int m);
6063
void incrementMachineLoad(int m, const Edge<T> *e);
64+
void incrementMachineWeight(int m, const Edge<T> *e);
6165
int getMinLoad();
6266
int getMaxLoad();
67+
int getMachineWithMinWeight();
68+
int getMachineWithMinWeight(const std::set<int> &partitions);
6369
std::vector<int> getMachines_load();
6470
int getTotalReplicas();
6571
int getNumVertices();
@@ -70,12 +76,22 @@ namespace CXXGRAPH
7076
const PartitionMap<T> &getPartitionMap();
7177
};
7278
template <typename T>
73-
CoordinatedPartitionState<T>::CoordinatedPartitionState(Globals &G) : record_map(), GLOBALS(G), machines_load_edges_mutex(std::make_shared<std::mutex>()), machines_load_vertices_mutex(std::make_shared<std::mutex>()), record_map_mutex(std::make_shared<std::mutex>())
79+
CoordinatedPartitionState<T>::CoordinatedPartitionState(Globals &G)
80+
: record_map(),
81+
GLOBALS(G),
82+
machines_load_edges_mutex(std::make_shared<std::mutex>()),
83+
machines_load_vertices_mutex(std::make_shared<std::mutex>()),
84+
machines_weight_edges_mutex(std::make_shared<std::mutex>()),
85+
record_map_mutex(std::make_shared<std::mutex>())
7486
{
87+
machines_load_edges.reserve(GLOBALS.numberOfPartition);
88+
machines_load_vertices.reserve(GLOBALS.numberOfPartition);
89+
machines_weight_edges.reserve(GLOBALS.numberOfPartition);
7590
for (int i = 0; i < GLOBALS.numberOfPartition; ++i)
7691
{
7792
machines_load_edges.push_back(0);
7893
machines_load_vertices.push_back(0);
94+
machines_weight_edges.push_back(0);
7995
partition_map[i] = std::make_shared<PARTITIONING::Partition<T>>(i);
8096
}
8197
MAX_LOAD = 0;
@@ -102,6 +118,13 @@ namespace CXXGRAPH
102118
return machines_load_edges.at(m);
103119
}
104120

121+
template <typename T>
122+
int CoordinatedPartitionState<T>::getMachineWeight(int m)
123+
{
124+
std::lock_guard<std::mutex> lock(*machines_weight_edges_mutex);
125+
return machines_weight_edges.at(m);
126+
}
127+
105128
template <typename T>
106129
int CoordinatedPartitionState<T>::getMachineLoadVertices(int m)
107130
{
@@ -121,6 +144,23 @@ namespace CXXGRAPH
121144
partition_map[m]->addEdge(e);
122145
}
123146
template <typename T>
147+
void CoordinatedPartitionState<T>::incrementMachineWeight(int m, const Edge<T> *e)
148+
{
149+
std::lock_guard<std::mutex> lock(*machines_weight_edges_mutex);
150+
double edge_weight = CXXGRAPH::NEGLIGIBLE_WEIGHT;
151+
if (e->isWeighted().has_value() && e->isWeighted().value())
152+
{
153+
edge_weight = (dynamic_cast<const Weighted *>(e))->getWeight();
154+
}
155+
machines_weight_edges[m] = machines_weight_edges[m] + edge_weight;
156+
//double new_value = machines_weight_edges[m];
157+
//if (new_value > MAX_LOAD)
158+
//{
159+
// MAX_LOAD = new_value;
160+
//}
161+
partition_map[m]->addEdge(e);
162+
}
163+
template <typename T>
124164
int CoordinatedPartitionState<T>::getMinLoad()
125165
{
126166
std::lock_guard<std::mutex> lock(*machines_load_edges_mutex);
@@ -141,6 +181,44 @@ namespace CXXGRAPH
141181
return MAX_LOAD;
142182
}
143183
template <typename T>
184+
int CoordinatedPartitionState<T>::getMachineWithMinWeight()
185+
{
186+
std::lock_guard<std::mutex> lock(*machines_weight_edges_mutex);
187+
188+
double MIN_LOAD = std::numeric_limits<double>::max();
189+
int machine_id = 0;
190+
for (int i = 0; i < machines_weight_edges.size(); ++i)
191+
{
192+
double loadi = machines_weight_edges[i];
193+
if (loadi < MIN_LOAD)
194+
{
195+
MIN_LOAD = loadi;
196+
machine_id = i;
197+
}
198+
}
199+
200+
return machine_id;
201+
}
202+
template <typename T>
203+
int CoordinatedPartitionState<T>::getMachineWithMinWeight(const std::set<int> &partitions)
204+
{
205+
std::lock_guard<std::mutex> lock(*machines_weight_edges_mutex);
206+
207+
double MIN_LOAD = std::numeric_limits<double>::max();
208+
int machine_id = 0;
209+
for (const auto &partition_id : partitions)
210+
{
211+
double loadi = machines_weight_edges.at(partition_id);
212+
if (loadi < MIN_LOAD)
213+
{
214+
MIN_LOAD = loadi;
215+
machine_id = partition_id;
216+
}
217+
}
218+
219+
return machine_id;
220+
}
221+
template <typename T>
144222
std::vector<int> CoordinatedPartitionState<T>::getMachines_load()
145223
{
146224
std::lock_guard<std::mutex> lock(*machines_load_edges_mutex);

include/Partitioning/CoordinatedRecord.hpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,35 @@ namespace CXXGRAPH
5252
void incrementDegree();
5353

5454
void addAll(std::set<int> &set);
55-
std::set<int> intersection(CoordinatedRecord &x, CoordinatedRecord &y);
55+
std::set<int> partition_intersection(std::shared_ptr<CoordinatedRecord> other);
56+
std::set<int> partition_union(std::shared_ptr<CoordinatedRecord> other);
57+
std::set<int> partition_difference(std::shared_ptr<CoordinatedRecord> other);
5658
};
5759
template <typename T>
60+
std::set<int> CoordinatedRecord<T>::partition_intersection(std::shared_ptr<CoordinatedRecord> other)
61+
{
62+
std::set<int> result;
63+
set_intersection(this->partitions.begin(), this->partitions.end(), other->partitions.begin(), other->partitions.end(),
64+
std::inserter(result, result.begin()));
65+
return result;
66+
}
67+
template <typename T>
68+
std::set<int> CoordinatedRecord<T>::partition_union(std::shared_ptr<CoordinatedRecord> other)
69+
{
70+
std::set<int> result;
71+
set_union(this->partitions.begin(), this->partitions.end(), other->partitions.begin(), other->partitions.end(),
72+
std::inserter(result, result.begin()));
73+
return result;
74+
}
75+
template <typename T>
76+
std::set<int> CoordinatedRecord<T>::partition_difference(std::shared_ptr<CoordinatedRecord> other)
77+
{
78+
std::set<int> result;
79+
set_difference(this->partitions.begin(), this->partitions.end(), other->partitions.begin(), other->partitions.end(),
80+
std::inserter(result, result.begin()));
81+
return result;
82+
}
83+
template <typename T>
5884
CoordinatedRecord<T>::CoordinatedRecord() : partitions()
5985
{
6086
lock = new std::mutex();
@@ -120,14 +146,6 @@ namespace CXXGRAPH
120146
{
121147
partitions.insert(set.begin(), set.end());
122148
}
123-
template <typename T>
124-
std::set<int> CoordinatedRecord<T>::intersection(CoordinatedRecord &x, CoordinatedRecord &y)
125-
{
126-
std::set<int> result;
127-
set_intersection(x.partitions.begin(), x.partitions.end(), y.partitions.begin(), y.partitions.end(),
128-
std::inserter(result, result.begin()));
129-
return result;
130-
}
131149
}
132150
}
133151

include/Partitioning/PartitionAlgorithm.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ namespace CXXGRAPH
3333
GREEDY_VC_ALG, ///< A Greedy Algorithm
3434
HDRF_ALG, ///< High-Degree (are) Replicated First (HDRF) Algorithm (Stream-Based Vertex-Cut Partitioning)
3535
EBV_ALG, ///< Edge-Balanced Vertex-Cut Offline Algorithm (EBV)
36-
ALG_2
36+
ALG_2,
37+
WB_LIBRA, ///< Weighted Balanced Libra
3738
};
3839
typedef E_PartitionAlgorithm PartitionAlgorithm;
3940
}

include/Partitioning/PartitionState.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ namespace CXXGRAPH
3434
public:
3535
virtual std::shared_ptr<Record<T>> getRecord(int x) = 0;
3636
virtual int getMachineLoad(int m) = 0;
37+
virtual int getMachineWeight(int m) = 0;
3738
virtual int getMachineLoadVertices(int m) = 0;
38-
virtual void incrementMachineLoad(int m,const Edge<T>* e) = 0;
39+
virtual void incrementMachineLoad(int m, const Edge<T>* e) = 0;
40+
virtual void incrementMachineWeight(int m, const Edge<T>* e) = 0;
3941
virtual int getMinLoad() = 0;
4042
virtual int getMaxLoad() = 0;
43+
virtual int getMachineWithMinWeight() = 0;
44+
virtual int getMachineWithMinWeight(const std::set<int> &partitions) = 0;
4145
virtual std::vector<int> getMachines_load() = 0;
4246
virtual int getTotalReplicas() = 0;
4347
virtual int getNumVertices() = 0;

include/Partitioning/Partitioner.hpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "EdgeBalancedVertexCut.hpp"
3434
#include "GreedyVertexCut.hpp"
3535
#include "EBV.hpp"
36+
#include "WeightBalancedLibra.hpp"
3637

3738
namespace CXXGRAPH
3839
{
@@ -73,8 +74,32 @@ namespace CXXGRAPH
7374
} else if (GLOBALS.partitionStategy == PartitionAlgorithm::EBV_ALG)
7475
{
7576
algorithm = new EBV<T>(GLOBALS);
76-
}
77+
} else if (GLOBALS.partitionStategy == PartitionAlgorithm::WB_LIBRA)
78+
{
79+
// precompute weight sum
80+
double weight_sum = 0.0;
81+
for (const auto &edge_it : *(this->dataset))
82+
{
83+
weight_sum += (edge_it->isWeighted().has_value() && edge_it->isWeighted().value()) ? dynamic_cast<const Weighted *>(edge_it)->getWeight() : CXXGRAPH::NEGLIGIBLE_WEIGHT;
84+
}
85+
double lambda = std::max(1.0, GLOBALS.param1);
86+
double P = static_cast<double>(GLOBALS.numberOfPartition);
87+
// avoid divide by zero when some parameters are invalid
88+
double weight_sum_bound = (GLOBALS.numberOfPartition == 0) ? 0.0 : lambda * weight_sum / P;
7789

90+
// precompute degrees of vertices
91+
std::unordered_map<std::size_t, int> vertices_degrees;
92+
for (const auto &edge_it : *(this->dataset))
93+
{
94+
auto nodePair = edge_it->getNodePair();
95+
std::size_t u = nodePair.first->getId();
96+
std::size_t v = nodePair.second->getId();
97+
vertices_degrees[u]++;
98+
vertices_degrees[v]++;
99+
}
100+
101+
algorithm = new WeightBalancedLibra<T>(GLOBALS, weight_sum_bound, move(vertices_degrees));
102+
}
78103
}
79104

80105
template <typename T>
@@ -93,6 +118,31 @@ namespace CXXGRAPH
93118
} else if (GLOBALS.partitionStategy == PartitionAlgorithm::EBV_ALG)
94119
{
95120
algorithm = new EBV<T>(GLOBALS);
121+
} else if (GLOBALS.partitionStategy == PartitionAlgorithm::WB_LIBRA)
122+
{
123+
// precompute weight sum
124+
double weight_sum = 0.0;
125+
for (const auto &edge_it : *(this->dataset))
126+
{
127+
weight_sum += (edge_it->isWeighted().has_value() && edge_it->isWeighted().value()) ? dynamic_cast<const Weighted *>(edge_it)->getWeight() : CXXGRAPH::NEGLIGIBLE_WEIGHT;
128+
}
129+
double lambda = GLOBALS.param1;
130+
double P = static_cast<double>(GLOBALS.numberOfPartition);
131+
// avoid divide by zero when some parameters are invalid
132+
double weight_sum_bound = (GLOBALS.numberOfPartition == 0) ? 0.0 : lambda * weight_sum / P;
133+
134+
// precompute degrees of vertices
135+
std::unordered_map<std::size_t, int> vertices_degrees;
136+
for (const auto &edge_it : *(this->dataset))
137+
{
138+
auto nodePair = edge_it->getNodePair();
139+
std::size_t u = nodePair.first->getId();
140+
std::size_t v = nodePair.second->getId();
141+
vertices_degrees[u]++;
142+
vertices_degrees[v]++;
143+
}
144+
145+
algorithm = new WeightBalancedLibra<T>(GLOBALS, weight_sum_bound, move(vertices_degrees));
96146
}
97147
}
98148

include/Partitioning/Utility/Globals.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,18 @@ namespace CXXGRAPH {
5454
};
5555

5656
inline Globals::Globals(int numberOfPartiton, PartitionAlgorithm algorithm,double param1, double param2, double param3, unsigned int threads)
57-
{
57+
{
5858
this->numberOfPartition = numberOfPartiton;
5959
this->partitionStategy = algorithm;
6060
this->threads = threads;
6161
this->param1 = param1;
6262
this->param2 = param2;
6363
this->param3 = param3;
64+
if (this->numberOfPartition <= 0)
65+
{
66+
std::cout << "ERROR: numberOfPartition " << numberOfPartition << std::endl;
67+
exit(-1);
68+
}
6469
}
6570

6671
inline Globals::~Globals()

0 commit comments

Comments
 (0)