-
Notifications
You must be signed in to change notification settings - Fork 0
/
compression_edge_spectral_sparsify.cc
154 lines (125 loc) · 4.24 KB
/
compression_edge_spectral_sparsify.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) 2019 ETH-Zurich.
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "benchmark.h"
#include "command_line.h"
#include <algorithm>
#include <cassert>
#include <omp.h>
#define LOCKS_FACTOR 10
double SG_fRand(double fMin, double fMax) {
double f = (double)rand() / RAND_MAX;
return fMin + f * (fMax - fMin);
}
void SG_spectral_sparsify_directed( NodeID origin, NodeID target, double Y, const Graph &g, std::vector<int64_t>** sampled_edges ) {
double rnd = SG_fRand(0, 1);
double edge_stays = std::min(1.0, Y / std::min(g.out_degree(origin), g.in_degree(target)));
if( edge_stays >= rnd ) {
sampled_edges[origin]->push_back(target);
}
}
void SG_spectral_sparsify_undirected( NodeID u, NodeID v, double Y, int64_t locks_factor,
const Graph &g, std::vector<int64_t>** sampled_edges, omp_nest_lock_t* locks ) {
double rnd = SG_fRand(0, 1);
double edge_stays = std::min(1.0, Y / std::min(g.out_degree(u), g.in_degree(v)));
if( edge_stays >= rnd ) {
omp_set_nest_lock(&locks[u / locks_factor]);
omp_set_nest_lock(&locks[v / locks_factor]);
sampled_edges[u]->push_back(v);
sampled_edges[v]->push_back(u);
omp_unset_nest_lock(&locks[u / locks_factor]);
omp_unset_nest_lock(&locks[v / locks_factor]);
}
}
int main(int argc, char* argv[]) {
// seed random number generator
srand((unsigned)time(0));
CLApp cli(argc, argv, "single-edge compression kernel (random uniform)");
if (!cli.ParseArgs()) {
return -1;
}
std::string g_output_file_name = cli.output_filename();
double p = cli.sampling_propability();
std::string spectral_variant = cli.spectral_variant();
assert( (p >= 0) && (p <= 1) );
// build graph
Builder b(cli);
Graph g = b.MakeGraph();
int64_t n = g.num_nodes();
// determine connectivity spectral parameter Y
double Y;
if( spectral_variant == "log" ) {
Y = p * log2((double)n);
} else {
if( spectral_variant == "avg" ) {
double avg_deg = 0;
#pragma omp parallel for reduction(+ : avg_deg)
for(int64_t v = 0; v < n; ++v) {
avg_deg += g.out_degree(v);
}
avg_deg /= (double)n;
Y = p * avg_deg;
} else {
std::cerr << "Parameter v needs to have one of two values: 'avg' or 'log'." << std::endl;
return -1;
}
}
std::vector<int64_t>** sampled_edges = new std::vector<int64_t>*[n];
#pragma omp parallel for
for(int64_t v = 0; v < n; ++v) {
sampled_edges[v] = new std::vector<int64_t>();
}
if(g.directed()) {
#pragma omp parallel for schedule(dynamic, 64)
for (NodeID u = 0; u < n; u++) {
for (NodeID v : g.out_neigh(u)) {
SG_spectral_sparsify_directed( u, v, Y, g, sampled_edges );
}
}
} else {
// graph is undirected
int locks_factor = LOCKS_FACTOR;
int64_t locks_nr = (n / locks_factor) + 1;
omp_nest_lock_t* locks = new omp_nest_lock_t[locks_nr]();
#pragma omp parallel for
for(int64_t i = 0; i < locks_nr; ++i) {
omp_init_nest_lock(&locks[i]);
}
#pragma omp parallel for schedule(dynamic, 64)
for (NodeID u = 0; u < n; u++) {
for (NodeID v : g.out_neigh(u)) {
if (v < u) {
SG_spectral_sparsify_undirected( u, v, Y, locks_factor, g, sampled_edges, locks );
}
}
}
#pragma omp parallel for
for(int64_t i = 0; i < locks_nr; ++i) {
omp_destroy_nest_lock(&locks[i]);
}
delete [] locks;
}
// write out the edges sorted: first by origin, then by target
#pragma omp parallel for
for (int64_t i = 0; i < n; i++) {
std::sort(sampled_edges[i]->begin(), sampled_edges[i]->end());
// TODO: Why do we need that?
// sampled_edges[i]->erase( unique(sampled_edges[i]->begin(), sampled_edges[i]->end() ), sampled_edges[i]->end() );
}
// write out the compressed graph
std::ofstream compressed_graph_file(g_output_file_name);
for (NodeID i = 0; i < n; i++) {
for (size_t j=0 ; j < sampled_edges[i]->size() ; j++) {
compressed_graph_file << i << " " << (*(sampled_edges[i]))[j] << std::endl;
}
}
compressed_graph_file.close();
#pragma omp parallel for
for(int64_t i = 0; i < g.num_nodes(); ++i) {
delete sampled_edges[i];
}
delete [] sampled_edges;
return 0;
}