GraphLite 计算有向图三角形

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;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值