void IncEval()

in analytical_engine/apps/clustering/clustering.h [73:272]


  void IncEval(const fragment_t& frag, context_t& ctx,
               message_manager_t& messages) {
    using vid_t = typename context_t::vid_t;
    auto inner_vertices = frag.InnerVertices();
    auto outer_vertices = frag.OuterVertices();

    if (ctx.stage == 0) {
      ctx.stage = 1;
      messages.ParallelProcess<fragment_t, int>(
          thread_num(), frag,
          [&ctx](int tid, vertex_t u, int msg) { ctx.global_degree[u] = msg; });

      ForEach(inner_vertices, [this, &frag, &ctx, &messages](int tid,
                                                             vertex_t v) {
        if (filterByDegree(frag, ctx, v)) {
          return;
        }
        int degree = ctx.global_degree[v];
        if (degree > 1) {
          vid_t u_gid, v_gid;
          auto& nbr_vec = ctx.complete_neighbor[v];
          nbr_vec.reserve(degree);
          std::vector<std::pair<vid_t, uint32_t>> msg_vec;
          msg_vec.reserve(degree);

          std::unordered_map<vid_t, uint32_t> is_rec;
          auto es = frag.GetOutgoingAdjList(v);
          for (auto& e : es) {
            auto u = e.get_neighbor();
            is_rec[u.GetValue()]++;
          }

          if (frag.directed()) {
            es = frag.GetIncomingAdjList(v);
            for (auto& e : es) {
              auto u = e.get_neighbor();
              is_rec[u.GetValue()]++;
              if (is_rec[u.GetValue()] == 2) {
                ctx.rec_degree[v]++;
              }
            }
          }

          es = frag.GetOutgoingAdjList(v);
          for (auto& e : es) {
            auto u = e.get_neighbor();
            if (ctx.global_degree[u] < ctx.global_degree[v]) {
              std::pair<vid_t, uint32_t> msg;
              msg.first = frag.Vertex2Gid(u);
              if (is_rec[u.GetValue()] == 2) {
                msg.second = 2;
              } else {
                msg.second = 1;
              }
              msg_vec.push_back(msg);
              nbr_vec.push_back(std::make_pair(u, msg.second));
            } else if (ctx.global_degree[u] == ctx.global_degree[v]) {
              u_gid = frag.Vertex2Gid(u);
              v_gid = frag.GetInnerVertexGid(v);
              if (v_gid > u_gid) {
                std::pair<vid_t, uint32_t> msg;
                msg.first = frag.Vertex2Gid(u);
                if (is_rec[u.GetValue()] == 2) {
                  msg.second = 2;
                } else {
                  msg.second = 1;
                }
                nbr_vec.push_back(std::make_pair(u, msg.second));
                msg_vec.push_back(msg);
              }
            }
          }

          if (frag.directed()) {
            es = frag.GetIncomingAdjList(v);
            for (auto& e : es) {
              auto u = e.get_neighbor();
              if (ctx.global_degree[u] < ctx.global_degree[v]) {
                std::pair<vid_t, uint32_t> msg;
                msg.first = frag.Vertex2Gid(u);
                if (is_rec[u.GetValue()] == 1) {
                  msg.second = 1;
                  msg_vec.push_back(msg);
                  nbr_vec.push_back(std::make_pair(u, 1));
                }
              } else if (ctx.global_degree[u] == ctx.global_degree[v]) {
                u_gid = frag.Vertex2Gid(u);
                v_gid = frag.GetInnerVertexGid(v);
                if (v_gid > u_gid) {
                  std::pair<vid_t, uint32_t> msg;
                  msg.first = frag.Vertex2Gid(u);
                  if (is_rec[u.GetValue()] == 1) {
                    msg.second = 1;
                    msg_vec.push_back(msg);
                    nbr_vec.push_back(std::make_pair(u, 1));
                  }
                }
              }
            }
          }

          messages.SendMsgThroughEdges<fragment_t,
                                       std::vector<std::pair<vid_t, uint32_t>>>(
              frag, v, msg_vec, tid);
        }
      });
      messages.ForceContinue();
    } else if (ctx.stage == 1) {
      ctx.stage = 2;
      messages
          .ParallelProcess<fragment_t, std::vector<std::pair<vid_t, uint32_t>>>(
              thread_num(), frag,
              [this, &frag, &ctx](
                  int tid, vertex_t u,
                  const std::vector<std::pair<vid_t, uint32_t>>& msg) {
                if (frag.IsInnerVertex(u) && filterByDegree(frag, ctx, u)) {
                  return;
                }
                auto& nbr_vec = ctx.complete_neighbor[u];
                for (auto m : msg) {
                  auto gid = m.first;
                  vertex_t v;
                  if (frag.Gid2Vertex(gid, v)) {
                    nbr_vec.push_back(std::make_pair(v, m.second));
                  }
                }
              });

      std::vector<typename FRAG_T::template vertex_array_t<uint32_t>>
          vertexsets(thread_num());
      ForEach(
          inner_vertices,
          [&vertexsets, &frag](int tid) {
            auto& ns = vertexsets[tid];
            ns.Init(frag.Vertices(), 0);
          },
          [&vertexsets, &ctx](int tid, vertex_t v) {
            if (ctx.global_degree[v] > 1) {
              auto& v0_nbr_set = vertexsets[tid];
              auto& v0_nbr_vec = ctx.complete_neighbor[v];
              for (auto u : v0_nbr_vec) {
                v0_nbr_set[u.first] = u.second;
              }
              for (auto u : v0_nbr_vec) {
                auto& v1_nbr_vec = ctx.complete_neighbor[u.first];
                for (auto w : v1_nbr_vec) {
                  if (v0_nbr_set[w.first] != 0) {
                    grape::atomic_add(
                        ctx.tricnt[u.first],
                        v0_nbr_set[w.first] * u.second * w.second);
                    grape::atomic_add(ctx.tricnt[v], v0_nbr_set[w.first] *
                                                         u.second * w.second);
                    grape::atomic_add(
                        ctx.tricnt[w.first],
                        v0_nbr_set[w.first] * u.second * w.second);
                  }
                }
              }
              for (auto u : v0_nbr_vec) {
                v0_nbr_set[u.first] = 0;
              }
            }
          },
          [](int tid) {});

      ForEach(outer_vertices, [&messages, &frag, &ctx](int tid, vertex_t v) {
        if (ctx.tricnt[v] != 0) {
          messages.SyncStateOnOuterVertex<fragment_t, int>(frag, v,
                                                           ctx.tricnt[v], tid);
        }
      });
      messages.ForceContinue();
    } else if (ctx.stage == 2) {
      ctx.stage = 3;
      messages.ParallelProcess<fragment_t, int>(
          thread_num(), frag, [&ctx](int tid, vertex_t u, int deg) {
            grape::atomic_add(ctx.tricnt[u], static_cast<uint32_t>(deg));
          });

      // output result to context data
      auto& global_degree = ctx.global_degree;
      auto& rec_degree = ctx.rec_degree;
      auto& tricnt = ctx.tricnt;
      auto& ctx_data = ctx.data();
      for (auto v : inner_vertices) {
        if (global_degree[v] == 0 || global_degree[v] == 1) {
          ctx_data[v] = 0;
        } else {
          int degree =
              global_degree[v] * (global_degree[v] - 1) - 2 * rec_degree[v];
          // Refer to https://en.wikipedia.org/wiki/Clustering_coefficient
          if (frag.directed()) {
            ctx_data[v] = degree == 0 ? 0.0 : 1.0 * tricnt[v] / degree;
          } else {
            ctx_data[v] = degree == 0 ? 0.0 : 2.0 * tricnt[v] / degree;
          }
        }
      }
    }
  }