graphlite 是一个开源同步图运算工具:https://github.com/schencoding/GraphLite,由中科院计算所的老师实现并开源。
本问题由国科大(UCAS) 大数据系统课程第二次作业得到,代码得分为满分,仅供参考。
题目:
如上图所示,输入一个有向图,箭头表示从一个顶点指向另一个顶点,= 号连接的表示箭头方向是任意的,求计算各个类型三角形的数目。
代码的英文注释中包含了详细的解题思路:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <map>
#include <vector>
#include "GraphLite.h"
#define VERTEX_CLASS_NAME(name) DirectedTriangleCount##name
/* Custom result type. */
typedef struct
{
int through_num;
int cycle_num;
} output_num;
/* InputFormatter to obtain the input record. */
class VERTEX_CLASS_NAME(InputFormatter) : public InputFormatter
{
public:
int64_t getVertexNum()
{
unsigned long long n;
sscanf(m_ptotal_vertex_line, "%lld", &n);
m_total_vertex = n;
return m_total_vertex;
}
int64_t getEdgeNum()
{
unsigned long long n;
sscanf(m_ptotal_edge_line, "%lld", &n);
m_total_edge = n;
return m_total_edge;
}
int getVertexValueSize()
{
m_n_value_size = sizeof(output_num);
return m_n_value_size;
}
int getEdgeValueSize()
{
m_e_value_size = sizeof(int);
return m_e_value_size;
}
int getMessageValueSize()
{
m_m_value_size = sizeof(int64_t);
return m_m_value_size;
}
void loadGraph()
{
unsigned long long last_vertex;
unsigned long long from;
unsigned long long to;
int weight = 0;
output_num value = {0, 0};
int outdegree = 0;
const char *line = getEdgeLine();
// Note: modify this if an edge weight is to be read
// modify the 'weight' variable
sscanf(line, "%lld %lld", &from, &to);
addEdge(from, to, &weight);
last_vertex = from;
++outdegree;
for (int64_t i = 1; i < m_total_edge; ++i)
{
line = getEdgeLine();
// Note: modify this if an edge weight is to be read
// modify the 'weight' variable
sscanf(line, "%lld %lld", &from, &to);
if (last_vertex != from)
{
addVertex(last_vertex, &value, outdegree);
last_vertex = from;
outdegree = 1;
}
else
{
++outdegree;
}
addEdge(from, to, &weight);
}
addVertex(last_vertex, &value, outdegree);
}
};
/* This is where the output is generated, return the expected number of the specific triangle. */
class VERTEX_CLASS_NAME(OutputFormatter) : public OutputFormatter
{
public:
void writeResult()
{
char s[1024];
int64_t vid;
output_num value;
ResultIterator r_iter;
r_iter.getIdValue(vid, &value);
int n = sprintf(s, "in: %d\nout: %d\nthrough: %d\ncycle: %d\n", value.through_num, value.through_num, value.through_num,
value.cycle_num);
writeNextResLine(s, n);
}
};
/* This is where the aggregator of the custom result type generated. */
class VERTEX_CLASS_NAME(Aggregator) : public Aggregator<output_num>
{
private:
output_num ans = {0, 0};
public:
void init()
{
m_global = ans;
m_local = ans;
}
void *getGlobal()
{
return &m_global;
}
void setGlobal(const void *p)
{
m_global.through_num = (*(output_num *)p).through_num;
m_global.cycle_num = (*(output_num *)p).cycle_num;
}
void *getLocal()
{
return &m_local;
}
void merge(const void *p)
{
m_global.through_num += (*(output_num *)p).through_num;
m_global.cycle_num += (*(output_num *)p).cycle_num;
}
void accumulate(const void *p)
{
m_local.through_num += (*(output_num *)p).through_num;
m_local.cycle_num += (*(output_num *)p).cycle_num;
}
};
/*
The main vertex program with compute().
For vertex v in superstep:
0. send messages to all its neighbors its vertexId and record all its neighbors.
1. get its parent neighbors from messages of the last superstep, and send them to its neighbors.
2. get its grandparent neighbors from messages of the last superstep, and compare them with its
own parent neighbors and children neighbors. For if the the grandparent neighbor is also one of the
parent neighbors, through number plus one. Otherwise, if the grandparent neighbor is also one of the
children neighbors, then the cycle number plus one. In-number and out-number is same as the through number.
3. record the aggregator, and voteToHalt().
*/
class VERTEX_CLASS_NAME() : public Vertex<output_num, int, int64_t>
{
private:
map<int64_t, vector<int64_t>> from_set;
map<int64_t, vector<int64_t>> to_set;
public:
void compute(MessageIterator *pmsgs)
{
int64_t vertex_id = getVertexId();
if (getSuperstep() == 0)
{
vector<int64_t> &to_set_of_vertex_id = to_set[vertex_id];
OutEdgeIterator itr = getOutEdgeIterator();
for (; !itr.done(); itr.next())
{
to_set_of_vertex_id.push_back(itr.target());
}
sendMessageToAllNeighbors(vertex_id);
}
else if (getSuperstep() == 1)
{
vector<int64_t> &from_set_of_vertex_id = from_set[vertex_id];
for (; !pmsgs->done(); pmsgs->next())
{
from_set_of_vertex_id.push_back(pmsgs->getValue());
}
for (int i = 0; i < from_set_of_vertex_id.size(); i++)
{
sendMessageToAllNeighbors(from_set_of_vertex_id[i]);
}
}
else if (getSuperstep() == 2)
{
vector<int64_t> grandfather_from_set_of_vertex_id;
for (; !pmsgs->done(); pmsgs->next())
{
grandfather_from_set_of_vertex_id.push_back(pmsgs->getValue());
}
vector<int64_t> &from_set_of_vertex_id = from_set[vertex_id];
for (vector<int64_t>::iterator it = grandfather_from_set_of_vertex_id.begin(); it != grandfather_from_set_of_vertex_id.end(); it++)
{
if (find(from_set_of_vertex_id.begin(), from_set_of_vertex_id.end(), *it) != from_set_of_vertex_id.end())
{
output_num ans = {1, 0};
accumulateAggr(0, &ans);
}
}
vector<int64_t> &to_set_of_vertex_id = to_set[vertex_id];
for (vector<int64_t>::iterator it = grandfather_from_set_of_vertex_id.begin(); it != grandfather_from_set_of_vertex_id.end(); it++)
{
if (find(to_set_of_vertex_id.begin(), to_set_of_vertex_id.end(), *it) != to_set_of_vertex_id.end())
{
output_num ans = {0, 1};
accumulateAggr(0, &ans);
}
}
}
else if (getSuperstep() == 3)
{
*mutableValue() = *(output_num *)getAggrGlobal(0);
voteToHalt();
return;
}
}
};
/*
Set the running configuration here.
*/
class VERTEX_CLASS_NAME(Graph) : public Graph
{
public:
VERTEX_CLASS_NAME(Aggregator) * aggregator;
public:
// argv[0]: PageRankVertex.so
// argv[1]: <input path>
// argv[2]: <output path>
void init(int argc, char *argv[])
{
setNumHosts(5);
setHost(0, "localhost", 1411);
setHost(1, "localhost", 1421);
setHost(2, "localhost", 1431);
setHost(3, "localhost", 1441);
setHost(4, "localhost", 1451);
if (argc < 3)
{
printf("Usage: %s <input path> <output path>\n", argv[0]);
exit(1);
}
m_pin_path = argv[1];
m_pout_path = argv[2];
aggregator = new VERTEX_CLASS_NAME(Aggregator)[1];
regNumAggr(1);
regAggr(0, &aggregator[0]);
}
void term()
{
delete[] aggregator;
}
};
/* STOP: do not change the code below. */
extern "C" Graph *create_graph()
{
Graph *pgraph = new VERTEX_CLASS_NAME(Graph);
pgraph->m_pin_formatter = new VERTEX_CLASS_NAME(InputFormatter);
pgraph->m_pout_formatter = new VERTEX_CLASS_NAME(OutputFormatter);
pgraph->m_pver_base = new VERTEX_CLASS_NAME();
return pgraph;
}
extern "C" void destroy_graph(Graph *pobject)
{
delete (VERTEX_CLASS_NAME() *)(pobject->m_pver_base);
delete (VERTEX_CLASS_NAME(OutputFormatter) *)(pobject->m_pout_formatter);
delete (VERTEX_CLASS_NAME(InputFormatter) *)(pobject->m_pin_formatter);
delete (VERTEX_CLASS_NAME(Graph) *)pobject;
}