【无标题】

Gemini图计算框架中提供的例子之bfs

这是gemini中的bfs例子,我写了些注释,但是有些东西不太懂,希望有人看到,指导一下,主要是忙信号的函数里面的dst变量,是不是激活节点的邻居,它的源代码没有看得太仔细,所以一些东西还不会,希望把那几个例子看了。
有一些好的图计算论文欢迎推荐。

#include <stdio.h>
#include <stdlib.h>

#include "core/graph.hpp"

void compute(Graph<Empty> * graph, VertexId root) {
  double exec_time = 0;
  exec_time -= get_time();
  //记录全部节点的属性值
  VertexId * parent = graph->alloc_vertex_array<VertexId>();
  //记录访问过的节点
  VertexSubset * visited = graph->alloc_vertex_subset();
  //迭代开始时激活节点
  VertexSubset * active_in = graph->alloc_vertex_subset();
  //迭代结束后激活节点
  VertexSubset * active_out = graph->alloc_vertex_subset();
  
  visited->clear();
  //记录root为访问过
  visited->set_bit(root);
  active_in->clear();
  //设置root为激活节点
  active_in->set_bit(root);
  //设置parent全为最大值
  graph->fill_vertex_array(parent, graph->vertices);
  //为root节点设置属性值
  parent[root] = root;
  //活跃节点数为1,即root
  VertexId active_vertices = 1;

  for (int i_i=0;active_vertices>0;i_i++) {
    //活跃节点数输出
    if (graph->partition_id==0) {
      printf("active(%d)>=%u\n", i_i, active_vertices);
    }
    active_out->clear();
    //边处理
    active_vertices = graph->process_edges<VertexId,VertexId>(
      //空闲信号函数
      [&](VertexId src){
      //发送空闲信号,第一个参数为发送源,第二个为发送信息
        graph->emit(src, src);
      },
      //空闲信号的槽函数,信号源、信号内容、信号源的邻居
      [&](VertexId src, VertexId msg, VertexAdjList<Empty> outgoing_adj){
        //激活的节点数
        VertexId activated = 0;
        //遍历出度邻居节点
        for (AdjUnit<Empty> * ptr=outgoing_adj.begin;ptr!=outgoing_adj.end;ptr++) {
          VertexId dst = ptr->neighbour;
          //没有访问的节点进行访问,并修改parent和下一轮迭代的激活
          if (parent[dst]==graph->vertices && cas(&parent[dst], graph->vertices, src)) {
            active_out->set_bit(dst);
            activated += 1;
          }
        }
        //返回本轮激活的节点数
        return activated;
      },
      //忙信号 这里的dst 我认为是激活节点的邻居。。。我也不太清楚。。。
      [&](VertexId dst, VertexAdjList<Empty> incoming_adj) {
        
        if (visited->get_bit(dst)) return;
        //如果没有访问过,寻找其邻居节点,当邻居节点为激活节点时发送信号,并退出
        for (AdjUnit<Empty> * ptr=incoming_adj.begin;ptr!=incoming_adj.end;ptr++) {
          VertexId src = ptr->neighbour;
          if (active_in->get_bit(src)) {
            graph->emit(dst, src);
            break;
          }
        }
      },
      [&](VertexId dst, VertexId msg) {
          //设置为激活节点
        if (cas(&parent[dst], graph->vertices, msg)) {
          active_out->set_bit(dst);
          return 1;
        }
        return 0;
      },
      active_in, visited
    );
    //修改visited 这里的激活节点数和边处理的返回值应该是一样的吧?
    active_vertices = graph->process_vertices<VertexId>(
      [&](VertexId vtx) {
        visited->set_bit(vtx);
        return 1;
      },
      active_out
    );
    //更新激活节点
    std::swap(active_in, active_out);
  }

  exec_time += get_time();
  if (graph->partition_id==0) {
    printf("exec_time=%lf(s)\n", exec_time);
  }
  //聚集函数,通过MPI  Send和Recv函数实现parent的同步,同步到进程0中
  graph->gather_vertex_array(parent, 0);
  //0号进程通过parent统计dfs遍历的结果
  if (graph->partition_id==0) {
    VertexId found_vertices = 0;
    for (VertexId v_i=0;v_i<graph->vertices;v_i++) {
      if (parent[v_i] < graph->vertices) {
        found_vertices += 1;
      }
    }
    printf("found_vertices = %u\n", found_vertices);
  }

  graph->dealloc_vertex_array(parent);
  delete active_in;
  delete active_out;
  delete visited;
}

int main(int argc, char ** argv) {
  MPI_Instance mpi(&argc, &argv);

  if (argc<4) {
    printf("bfs [file] [vertices] [root]\n");
    exit(-1);
  }

  Graph<Empty> * graph;
  graph = new Graph<Empty>();
  VertexId root = std::atoi(argv[3]);
  graph->load_directed(argv[1], std::atoi(argv[2]));

  compute(graph, root);
  for (int run=0;run<5;run++) {
    compute(graph, root);
  }

  delete graph;
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值