Files
@ 1bdb42fca62f
Branch filter:
Location: AENC/switchchain/cpp/graph_ccm.hpp - annotation
1bdb42fca62f
5.5 KiB
text/x-c++hdr
Fix Constrained Configuration Model sampling
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 | 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 2c86fdd4152e 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 32c10aa21482 1bdb42fca62f 32c10aa21482 1bdb42fca62f 1bdb42fca62f 32c10aa21482 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 32c10aa21482 1bdb42fca62f 32c10aa21482 1bdb42fca62f 1bdb42fca62f 32c10aa21482 32c10aa21482 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 32c10aa21482 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 32c10aa21482 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 1bdb42fca62f 1bdb42fca62f 1bdb42fca62f 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 32c10aa21482 | #include "graph.hpp"
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>
//
// Assumes degree sequence does NOT contain any zeroes!
//
// method2 = true -> take highest degree and finish its pairing completely
// method2 = false -> take new highest degree after every pairing
template <typename RNG>
bool constrainedConfigurationModel(DegreeSequence &ds, Graph &g, RNG &rng,
bool method2) {
// Similar to Havel-Hakimi but instead of pairing up with the highest ones
// that remain, simply pair up with random ones
unsigned int n = ds.size();
// degree, vertex index
std::vector<std::pair<unsigned int, unsigned int>> degrees(n);
for (unsigned int i = 0; i < n; ++i) {
degrees[i].first = ds[i];
degrees[i].second = i;
}
// remaining half-edges , iterator into `degrees`
std::vector<std::pair<unsigned int, decltype(degrees.begin())>> available;
available.reserve(n);
// Clear the graph
g.reset(n);
while (!degrees.empty()) {
// Get the highest degree:
// If there are multiple highest ones, we pick the first one
unsigned int dmax = 0;
auto uIter = degrees.begin();
for (auto iter = degrees.begin(); iter != degrees.end(); ++iter) {
if (iter->first >= dmax) {
dmax = iter->first;
uIter = iter;
}
}
if (dmax > degrees.size() - 1)
return false;
if (dmax == 0) {
std::cerr << "ERROR 1 in CCM.\n";
return false;
}
unsigned int u = uIter->second;
// Pair with a random vertex that is not u itself and to which
// u has not paired yet!
// Uniform over all available half-edges, not available vertices
unsigned int availableEdges = 0;
available.clear();
for (auto iter = degrees.begin(); iter != degrees.end(); ++iter) {
if (iter->second != u && !g.hasEdge({u, iter->second})) {
availableEdges += iter->first;
available.push_back(std::make_pair(iter->first, iter));
}
}
if (availableEdges == 0)
return false;
if (method2) {
// Now assign randomly to the remaining vertices
// weighted by the number of half-edges they have left
auto vIter = uIter;
while (dmax--) {
std::uniform_int_distribution<> distr(1, availableEdges);
// Go from edge index to number. We should really have a proper
// data structure like some cumulative tree
unsigned int halfEdge = distr(rng);
unsigned int cumulative = 0;
for (auto iter = available.begin(); iter != available.end();
++iter) {
cumulative += iter->first;
if (halfEdge <= cumulative) {
vIter = iter->second;
availableEdges -= iter->first;
available.erase(iter);
break;
}
}
if (vIter == uIter)
std::cerr << "ERROR 1 in CCM2.\n";
if (vIter->first == 0)
std::cerr << "ERROR 2 in CCM2.\n";
if (!g.addEdge({u, vIter->second}))
std::cerr << "ERROR 3 in CCM2.\n";
uIter->first--;
vIter->first--;
}
for (auto iter = degrees.begin(); iter != degrees.end();)
if (iter->first == 0)
iter = degrees.erase(iter);
else
++iter;
} else {
std::uniform_int_distribution<> distr(1, availableEdges);
// Go from edge index to number. We should really have a proper
// data structure like some cumulative tree
auto vIter = uIter;
unsigned int halfEdge = distr(rng);
unsigned int cumulative = 0;
for (auto iter = available.begin(); iter != available.end();
++iter) {
cumulative += iter->first;
if (halfEdge <= cumulative) {
vIter = iter->second;
break;
}
}
// pair u to v
if (vIter->first == 0)
std::cerr << "ERROR 4 in CCM1.\n";
if (!g.addEdge({u, vIter->second}))
std::cerr << "ERROR 5. Could not add edge in CCM1.\n";
// Purge anything with degree zero
// Be careful with invalidating the other iterator!
// Degree of u is always greater or equal to the degree of v
if (dmax == 1) {
// Remove both
// Erasure invalidates all iterators AFTER the erased one
if (vIter > uIter) {
degrees.erase(vIter);
degrees.erase(uIter);
} else {
degrees.erase(uIter);
degrees.erase(vIter);
}
} else {
// Remove only v if it reaches zero
uIter->first--;
vIter->first--;
if (vIter->first == 0)
degrees.erase(vIter);
}
// degrees.erase(std::remove_if(degrees.begin(), degrees.end(),
// [](auto x) { return x.first == 0;
// }));
}
}
return true;
}
|