Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]Implement attribute assortativity app and numeric assortativity app #515

Merged
merged 42 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f499a5e
create assortativity
Ningsir Jul 5, 2021
97a461a
add degree assortativity
Ningsir Jul 7, 2021
6e8e4f4
format check
Ningsir Jul 9, 2021
174b364
format check
Ningsir Jul 9, 2021
5406cc1
format check
Ningsir Jul 11, 2021
6ceb0cc
implement attribute assortativity
Ningsir Jul 11, 2021
9694e0c
format check
Ningsir Jul 11, 2021
b2fa86e
add average degree connectivity test
Ningsir Jul 11, 2021
29b1e8f
implement average degree connectivity
Ningsir Jul 11, 2021
6dacecf
Merge branch 'alibaba:main' into main
Ningsir Jul 11, 2021
a3d99e2
make gsa_clformat
Ningsir Jul 12, 2021
c21f19e
delete degree and average degree apps
Ningsir Jul 12, 2021
7747786
Merge branch 'alibaba:main' into attribute
Ningsir Jul 15, 2021
56ec564
modify message format
Ningsir Jul 16, 2021
dfff260
implement attribute assortativity with python
Ningsir Jul 16, 2021
46c0165
Merge branch 'alibaba:main' into attribute
Ningsir Jul 16, 2021
76da2dd
support dynamic fragment
Ningsir Jul 16, 2021
969c5cd
implement attribute assortativity with python
Ningsir Jul 16, 2021
df21c53
Merge branch 'attribute' of https://github.com/Ningsir/GraphScope int…
Ningsir Jul 16, 2021
d9e913d
add #include <utility>
Ningsir Jul 20, 2021
3ecf5da
implement numeric assortativity
Ningsir Jul 20, 2021
a41081a
Merge branch 'alibaba:main' into attribute
Ningsir Jul 20, 2021
c28de84
implement numeric assortativity
Ningsir Jul 20, 2021
6107bbc
imlement numeric assortativity with python
Ningsir Jul 20, 2021
0e4850b
Merge branch 'attribute' of https://github.com/Ningsir/GraphScope int…
Ningsir Jul 20, 2021
c402fad
Merge branch 'main' into attribute
Ningsir Aug 10, 2021
c8ac969
support arrow fragment
Ningsir Aug 10, 2021
e1f064a
remove useless comments and refactor
Ningsir Aug 10, 2021
6132ad7
Merge branch 'main' into attribute
Ningsir Aug 29, 2021
04b78e5
add some comments
Ningsir Aug 29, 2021
87e3171
Merge branch 'alibaba:main' into attribute
Ningsir Aug 31, 2021
b2e08b6
remove attribute assortativity app in run_app.cc
Ningsir Aug 31, 2021
a2efc13
Merge branch 'alibaba:main' into attribute
Ningsir Sep 10, 2021
b1b8416
remove repeated codes
Ningsir Sep 10, 2021
307598e
Merge branch 'attribute' of https://github.com/Ningsir/GraphScope int…
Ningsir Sep 10, 2021
f993159
Merge branch 'alibaba:main' into attribute
Ningsir Sep 19, 2021
3e0e268
merge attribute and numeric assortativity app
Ningsir Sep 19, 2021
d00e9b5
fix attribute mixing matrix function
Ningsir Sep 19, 2021
2e7b2f1
Merge branch 'attribute' of https://github.com/Ningsir/GraphScope int…
Ningsir Sep 19, 2021
05444ac
convert vdata_t to double in compile-time
Ningsir Sep 20, 2021
d63f5da
call graphscope.xxx
Ningsir Sep 22, 2021
65316a0
Merge branch 'alibaba:main' into attribute
Ningsir Sep 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
/** Copyright 2020 Alibaba Group Holding Limited.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Author: Ning Xin
*/

#ifndef ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_H_
#define ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_H_

#include <unordered_map>
#include <utility>
#include <vector>

#include "grape/grape.h"

#include "apps/assortativity/attribute/attribute_assortativity_context.h"
#include "apps/assortativity/utils.h"
#include "core/app/app_base.h"
#include "core/utils/app_utils.h"
#include "core/worker/default_worker.h"

namespace gs {
/**
* @brief Compute the attribute assortativity or numeric assortativity for
* graph. The parameter numeric in context determines which app to use.
* If numeric is true, it is numeric assortativity app, else attribute
* assortativity app. Assortativity measures the similarity of connections in
* the graph with respect to the attribute.
* @tparam FRAG_T
*/
template <typename FRAG_T>
class AttributeAssortativity
: public AppBase<FRAG_T, AttributeAssortativityContext<FRAG_T>>,
public grape::Communicator {
public:
INSTALL_DEFAULT_WORKER(AttributeAssortativity<FRAG_T>,
AttributeAssortativityContext<FRAG_T>, FRAG_T)
static constexpr grape::MessageStrategy message_strategy =
grape::MessageStrategy::kAlongEdgeToOuterVertex;
static constexpr grape::LoadStrategy load_strategy =
grape::LoadStrategy::kBothOutIn;
using vertex_t = typename fragment_t::vertex_t;
using vid_t = typename fragment_t::vid_t;
using oid_t = typename fragment_t::oid_t;
using vdata_t = typename fragment_t::vdata_t;

void PEval(const fragment_t& frag, context_t& ctx,
message_manager_t& messages) {
auto inner_vertices = frag.InnerVertices();
for (auto v : inner_vertices) {
ProcessVertex<vdata_t>(v, frag, ctx, messages);
}
messages.ForceContinue();
}

void IncEval(const fragment_t& frag, context_t& ctx,
message_manager_t& messages) {
if (!ctx.merge_stage) {
UpdateAttributeMixingMap<vertex_t, vdata_t>(frag, ctx, messages);
} else {
// merge in worker 0
if (frag.fid() == 0) {
MergeAttributeMixingMap<vdata_t>(ctx, messages);
std::vector<std::vector<double>> attribute_mixing_matrix;
// numeric assortativity app
if (ctx.numeric) {
std::unordered_map<int, double> map;
getNumericMixingMatrix(ctx, attribute_mixing_matrix, map);
// compute numeric assortativity
ctx.attribute_assortativity =
ProcessMatrix(attribute_mixing_matrix, map);
} else { // attribute assortativity app
getAttributeMixingMatrix(ctx, attribute_mixing_matrix);
// compute attribute assortativity
ctx.attribute_assortativity =
computeAssortativity(attribute_mixing_matrix);
}
// write result to ctx
std::vector<size_t> shape{1};
ctx.set_shape(shape);
ctx.assign(ctx.attribute_assortativity);
VLOG(0) << "attribute assortatity: " << ctx.attribute_assortativity
<< std::endl;
}
}
}
/**
* @brief count the attribute-attribute pairs
*
* @param source_data the data of source node
* @param target_data the data of target node
* @param ctx
*/
template <typename vdata_t, typename context_t>
inline void AttributeMixingCount(vdata_t source_data, vdata_t target_data,
context_t& ctx) {
if (ctx.attribute_mixing_map.count(source_data) == 0 ||
ctx.attribute_mixing_map[source_data].count(target_data) == 0) {
ctx.attribute_mixing_map[source_data][target_data] = 1;
} else {
ctx.attribute_mixing_map[source_data][target_data] += 1;
}
}

/**
* @brief traverse the outgoing neighbors of vertex v and update the
* attribute-attribute pairs.
*
* @param v
* @param frag
* @param ctx
* @param messages
*/
template <typename vdata_t, typename vertex_t, typename fragment_t,
typename context_t, typename message_manager_t>
void ProcessVertex(const vertex_t& v, const fragment_t& frag, context_t& ctx,
message_manager_t& messages) {
vdata_t source_data = frag.GetData(v);
// get all neighbors of vertex v
auto oes = frag.GetOutgoingAdjList(v);
for (auto& e : oes) {
vertex_t neighbor = e.get_neighbor();
if (frag.IsOuterVertex(neighbor)) {
messages.SyncStateOnOuterVertex(frag, neighbor, source_data);
} else {
vdata_t target_data = frag.GetData(neighbor);
AttributeMixingCount(source_data, target_data, ctx);
}
}
}
/**
* @brief update the attribute-attribute pairs from the outer vertex.
*
* @param frag
* @param ctx
* @param messages
*/
template <typename vertex_t, typename vdata_t, typename fragment_t,
typename context_t, typename message_manager_t>
void UpdateAttributeMixingMap(const fragment_t& frag, context_t& ctx,
message_manager_t& messages) {
vdata_t source_data;
vertex_t u;
// update attribute mixing map
while (messages.GetMessage(frag, u, source_data)) {
vdata_t target_data = frag.GetData(u);
AttributeMixingCount(source_data, target_data, ctx);
}
ctx.merge_stage = true;
// send message to worker 0
if (frag.fid() != 0) {
messages.SendToFragment(0, ctx.attribute_mixing_map);
}
messages.ForceContinue();
}

/**
* @brief merge attribute mixing map of all workers in worker 0 and the result
* is saved in the contxt of worker 0.
*
* @param ctx
* @param messages
*
*/
template <typename vdata_t, typename context_t, typename message_manager_t>
void MergeAttributeMixingMap(context_t& ctx, message_manager_t& messages) {
std::unordered_map<vdata_t, std::unordered_map<vdata_t, int>> msg;
while (messages.GetMessage(msg)) {
for (auto& pair1 : msg) {
for (auto& pair2 : pair1.second) {
// merge
if (ctx.attribute_mixing_map.count(pair1.first) == 0 ||
ctx.attribute_mixing_map[pair1.first].count(pair2.first) == 0) {
ctx.attribute_mixing_map[pair1.first][pair2.first] = pair2.second;
} else {
ctx.attribute_mixing_map[pair1.first][pair2.first] += pair2.second;
}
}
}
}
}

private:
/**
* @brief Compute assortativity for attribute matrix attribute_mixing_matrix
*
* @param attribute_mixing_matrix n x n matrix
* @return attribute assortativity
*/
double computeAssortativity(
std::vector<std::vector<double>>& attribute_mixing_matrix) {
int n = attribute_mixing_matrix.size();
std::vector<double> a;
// sum of column
for (auto& row : attribute_mixing_matrix) {
a.emplace_back(accumulate(row.begin(), row.end(), 0.0));
}
std::vector<double> b;
// sum of row
for (int i = 0; i < n; i++) {
double sum = 0.0;
for (int j = 0; j < n; j++) {
sum += attribute_mixing_matrix[j][i];
}
b.emplace_back(sum);
}
double sum_eii = 0.0, sum_ai_bi = 0.0;
for (int i = 0; i < n; i++) {
sum_eii += attribute_mixing_matrix[i][i];
sum_ai_bi += a[i] * b[i];
}
return (sum_eii - sum_ai_bi) / (1 - sum_ai_bi);
}

/**
* @brief get attribute mixing matrix by attribute mixing map
*
* @param ctx
* @param[out] attribute_mixing_matrix
*/
void getAttributeMixingMatrix(
context_t& ctx,
std::vector<std::vector<double>>& attribute_mixing_matrix) {
int total_edge_num = 0;
// <data, index> pair, index:{0, 1, ..., n}
std::unordered_map<vdata_t, int> index_map;
int count = 0;
for (auto& pair1 : ctx.attribute_mixing_map) {
for (auto& pair2 : pair1.second) {
if (index_map.count(pair1.first) == 0) {
index_map[pair1.first] = count;
count++;
}
if (index_map.count(pair2.first) == 0) {
index_map[pair2.first] = count;
count++;
}
total_edge_num += pair2.second;
}
}
int n = index_map.size();
std::vector<std::vector<double>> tmp(n, std::vector<double>(n, 0.0));
attribute_mixing_matrix.swap(tmp);
for (auto& pair1 : ctx.attribute_mixing_map) {
for (auto& pair2 : pair1.second) {
int row = index_map[pair1.first];
int column = index_map[pair2.first];
attribute_mixing_matrix[row][column] =
pair2.second / static_cast<double>(total_edge_num);
}
}
}

/**
* @brief get numeric mixing matrix by attribute mixing map
*
* @param ctx
* @param[out] attribute_mixing_matrix
* @param[out] map index -> data of a node
*/
void getNumericMixingMatrix(
context_t& ctx, std::vector<std::vector<double>>& attribute_mixing_matrix,
std::unordered_map<int, double>& map) {
int total_edge_num = 0;
// <data, index> pair, index:{0, 1, ..., n}
std::unordered_map<vdata_t, int> index_map;
int count = 0;
for (auto& pair1 : ctx.attribute_mixing_map) {
for (auto& pair2 : pair1.second) {
if (index_map.count(pair1.first) == 0) {
index_map[pair1.first] = count;
vdata_t vdata = pair1.first;
double data = 1.0;
// convert vdata_t to double in compile-time
static_if<Conversion<double, vdata_t>::exists>(
[&](auto& data, auto& vdata) {
data = static_cast<double>(vdata);
})(data, vdata);
map[count] = data;
count++;
}
if (index_map.count(pair2.first) == 0) {
index_map[pair2.first] = count;
vdata_t vdata = pair2.first;
double data = 1.0;
// convert vdata_t to double in compile-time
static_if<Conversion<double, vdata_t>::exists>(
[&](auto& data, auto& vdata) {
data = static_cast<double>(vdata);
})(data, vdata);
map[count] = data;
count++;
}
total_edge_num += pair2.second;
}
}
int n = index_map.size();
std::vector<std::vector<double>> tmp(n, std::vector<double>(n, 0.0));
attribute_mixing_matrix.swap(tmp);
for (auto& pair1 : ctx.attribute_mixing_map) {
for (auto& pair2 : pair1.second) {
int row = index_map[pair1.first];
int column = index_map[pair2.first];
attribute_mixing_matrix[row][column] =
pair2.second / static_cast<double>(total_edge_num);
}
}
}
};
} // namespace gs

#endif // ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/** Copyright 2020 Alibaba Group Holding Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Ning Xin
*/

#ifndef ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_CONTEXT_H_
#define ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_CONTEXT_H_

#include <limits>
#include <string>
#include <unordered_map>
#include <utility>

#include "grape/grape.h"

#include "core/app/app_base.h"
#include "core/context/tensor_context.h"

namespace gs {
template <typename FRAG_T>
class AttributeAssortativityContext : public TensorContext<FRAG_T, double> {
public:
using vdata_t = typename FRAG_T::vdata_t;
explicit AttributeAssortativityContext(const FRAG_T& fragment)
: TensorContext<FRAG_T, double>(fragment) {}

void Init(grape::DefaultMessageManager& messages, bool numeric) {
merge_stage = false;
this->numeric = numeric;
}

void Output(std::ostream& os) override {
auto& frag = this->fragment();
if (frag.fid() == 0) {
os << attribute_assortativity << std::endl;
}
}
std::unordered_map<vdata_t, std::unordered_map<vdata_t, int>>
attribute_mixing_map;
double attribute_assortativity;
bool merge_stage;
// if true, it is numeric assortativity app else attribute assortativity app
bool numeric;
};
} // namespace gs

#endif // ANALYTICAL_ENGINE_APPS_ASSORTATIVITY_ATTRIBUTE_ATTRIBUTE_ASSORTATIVITY_CONTEXT_H_
Loading