Files @ 634d9c963986
Branch filter:

Location: AENC/switchchain/cpp/graph_ccm.hpp - annotation

Tom Bannink
Add insertion sort for HH and timed time-evols
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
32c10aa21482
1bdb42fca62f
1bdb42fca62f
1bdb42fca62f
1bdb42fca62f
1bdb42fca62f
2e3f21cc591d
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
2e3f21cc591d
2e3f21cc591d
32c10aa21482
32c10aa21482
2e3f21cc591d
32c10aa21482
2e3f21cc591d
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
            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;
                auto vIter = uIter;
                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;
                }
            }
            if (vIter == uIter)
                std::cerr << "ERROR 4 in CCM2.\n";
            // pair u to v
            if (vIter->first == 0)
                std::cerr << "ERROR 5 in CCM1.\n";
            if (!g.addEdge({u, vIter->second}))
                std::cerr << "ERROR 6. 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;
}