Files @ 32a7f1c13790
Branch filter:

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

Tom Bannink
Add cannonical powerlaw ds
0f3a4ccb62ea
bfca8e3039c5
f8cbbd135cc1
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0f3a4ccb62ea
28b33414825e
28b33414825e
b8a998539881
b8a998539881
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
6218fdc51593
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0290e63ba024
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
0f3a4ccb62ea
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
f8cbbd135cc1
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0c08dc618491
0c08dc618491
0f3a4ccb62ea
0f3a4ccb62ea
#pragma once
#include <algorithm>
#include <cassert>
#include <numeric>
#include <vector>
#include <iostream>

class Edge {
  public:
    unsigned int u, v;

    bool operator==(const Edge &e) const { return u == e.u && v == e.v; }
};

class StoredEdge {
  public:
    Edge e;
    // indices into adjacency lists
    // adj[u][u2vindex] = v;
    // adj[v][v2uindex] = u;
    unsigned int u2vindex, v2uindex;
};

class DiDegree {
  public:
    unsigned int in;
    unsigned int out;
};

typedef std::vector<unsigned int> DegreeSequence;
typedef std::vector<DiDegree> DiDegreeSequence;

class Graph {
  public:
    Graph() {}

    Graph(unsigned int n) { reset(n); }

    ~Graph() {}

    // Clears any previous edges and create
    // an empty graph on n vertices
    void reset(unsigned int n) {
        edges.clear();
        adj.resize(n);
        for (auto &v : adj)
            v.clear();
        badj.resize(n);
        for (auto &v : badj) {
            v.resize(n);
            v.assign(n, false);
        }
    }

    unsigned int edgeCount() const { return edges.size(); }

    const Edge &getEdge(unsigned int i) const { return edges[i].e; }

    const auto& getAdj() const { return adj; }

    const auto& getBooleanAdj() const { return badj; }

    // When the degree sequence is not graphics, the Graph can be
    // in any state, it is not neccesarily empty
    bool createFromDegreeSequence(const DegreeSequence &d) {
        // Havel-Hakimi algorithm
        // Based on Erdos-Gallai theorem

        unsigned int n = d.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 = d[i];
            degrees[i].second = i;
        }

        // Clear the graph
        reset(n);

        while (!degrees.empty()) {
            std::sort(degrees.begin(), degrees.end());
            // Highest degree is at back of the vector
            // Take it out
            unsigned int degree = degrees.back().first;
            unsigned int u = degrees.back().second;
            degrees.pop_back();
            if (degree > degrees.size()) {
                return false;
            }
            // Now loop over the last 'degree' entries of degrees
            auto rit = degrees.rbegin();
            for (unsigned int i = 0; i < degree; ++i) {
                if (rit->first == 0 || !addEdge({u, rit->second})) {
                    return false;
                }
                rit->first--;
                ++rit;
            }
        }
        return true;
    }

    DegreeSequence getDegreeSequence() const {
        DegreeSequence d(adj.size());
        std::transform(adj.begin(), adj.end(), d.begin(),
                       [](const auto &u) { return u.size(); });
        return d;
    }

    // Assumes valid vertex indices
    bool hasEdge(const Edge& e_) const {
        return badj[e_.u][e_.v];
        //Edge e;
        //if (adj[e_.u].size() <= adj[e_.v].size()) {
        //    e = e_;
        //} else {
        //    e.u = e_.v;
        //    e.v = e_.u;
        //}
        //for (unsigned int v : adj[e.u]) {
        //    if (v == e.v)
        //        return true;
        //}
        //return false;
    }

    bool addEdge(const Edge &e) {
        if (e.u >= adj.size() || e.v >= adj.size())
            return false;
        if (hasEdge(e))
            return false;
        StoredEdge se;
        se.e = e;
        se.u2vindex = adj[e.u].size();
        se.v2uindex = adj[e.v].size();
        adj[e.u].push_back(e.v);
        adj[e.v].push_back(e.u);
        edges.push_back(se);
        badj[e.u][e.v] = 1;
        badj[e.v][e.u] = 1;
        return true;
    }

    // There are two possible edge exchanges
    // switchType indicates which one is desired
    // Returns false if the switch is not possible
    bool exchangeEdges(unsigned int e1index, unsigned int e2index, bool switchType) {
        StoredEdge &se1 = edges[e1index];
        StoredEdge &se2 = edges[e2index];
        const Edge &e1 = se1.e;
        const Edge &e2 = se2.e;

        // The new edges configuration is one of these two
        // A) e1.u - e2.u and e1.v - e2.v
        // B) e1.u - e2.v and e2.u - e1.v
        // Note that to do (B) instead of (A), simply swap e2.u <-> e2.v
        // Now we can just consider switch type (A)
        if (switchType) {
            std::swap(se2.e.u, se2.e.v);
            std::swap(se2.u2vindex, se2.v2uindex);
        }

        // First check if the move is possible
        if (hasEdge({e1.u, e2.u}) || hasEdge({e1.v, e2.v}))
            return false; // conflicting edges

        // Clear old edges
        badj[e1.u][e1.v] = false;
        badj[e1.v][e1.u] = false;
        badj[e2.u][e2.v] = false;
        badj[e2.v][e2.u] = false;

        adj[e1.u][se1.u2vindex] = e2.u;
        adj[e1.v][se1.v2uindex] = e2.v;
        adj[e2.u][se2.u2vindex] = e1.u;
        adj[e2.v][se2.v2uindex] = e1.v;
        // Carefull: when updating se1,se2 also e1 and 2e change
        std::swap(se1.e.v, se2.e.u);
        std::swap(se1.v2uindex, se2.u2vindex);
        // e1 and e2 now contain the NEW edges!!
        badj[e1.u][e1.v] = true;
        badj[e1.v][e1.u] = true;
        badj[e2.u][e2.v] = true;
        badj[e2.v][e2.u] = true;
        return true;
    }

    int countTriangles() const {
        int triangles = 0;
        for (auto& v : adj) {
            for (unsigned int i = 0; i < v.size(); ++i) {
                for (unsigned int j = i + 1; j < v.size(); ++j) {
                    if (hasEdge({v[i], v[j]})) {
                        ++triangles;
                    }
                }
            }
        }
        assert(triangles % 3 == 0);
        return triangles / 3;
    }

    // Should return zero
    int consistencyCheck() const {
        // Check if info in 'edges' is present
        // in adj and badj
        for (auto &se : edges) {
            if (se.e.u >= adj.size() || se.e.v >= adj.size())
                return 1;
            if (!badj[se.e.u][se.e.v])
                return 2;
            if (!badj[se.e.v][se.e.u])
                return 3;
            if (se.u2vindex >= adj[se.e.u].size())
                return 4;
            if (se.v2uindex >= adj[se.e.v].size())
                return 5;
            if (adj[se.e.u][se.u2vindex] != se.e.v)
                return 6;
            if (adj[se.e.v][se.v2uindex] != se.e.u)
                return 7;
        }
        // Check if info in 'adj' is present
        // in badj and edges
        for (unsigned int u = 0; u < adj.size(); ++u) {
            for (unsigned int v : adj[u]) {
                if (!badj[u][v])
                    return 8;
                if (!badj[v][u])
                    return 9;
                // Check if it appears in edges
                bool found = false;
                for (auto &se : edges) {
                    if ((se.e.u == u && se.e.v == v) ||
                        (se.e.u == v && se.e.v == u)) {
                        found = true;
                        break;
                    }
                }
                if (!found)
                    return 10;
            }
        }
        // Check if info in 'badj' is present
        // in adj and edges
        // TODO
        return 0;
    }

  private:
    // Graph is saved in three formats for speed
    // They should be kept consistent at all times
    std::vector<std::vector<unsigned int>> adj;
    std::vector<std::vector<bool>> badj; // symmetric binary matrix
    std::vector<StoredEdge> edges;
};