← comparison · impl/tree_inl.h
1#ifndef JNGEN_INCLUDE_TREE_INL_H2#error File "tree_inl.h" must not be included directly.3#include "../tree.h" // for completion emgine4#endif56void Tree::addEdge(int u, int v, const Weight& w) {7    extend(std::max(u, v) + 1);89    u = vertexByLabel(u);10    v = vertexByLabel(v);1112    int ret = dsu_.unite(u, v);13    ensure(ret, "A cycle appeared in the tree");1415    addEdgeUnsafe(u, v);1617    if (!w.empty()) {18        setEdgeWeight(m() - 1, w);19    }20}2122bool Tree::canAddEdge(int u, int v) {23    u = vertexByLabel(u);24    v = vertexByLabel(v);25    return dsu_.getRoot(u) != dsu_.getRoot(v);26}2728Array Tree::parents(int root) const {29    ensure(isConnected(), "Tree::parents(int): Tree is not connected");30    root = vertexByLabel(root);3132    Array parents(n());33    parents[root] = -1;34    std::vector<int> used(n());35    std::vector<int> queue{root};36    for (size_t i = 0; i < queue.size(); ++i) {37        int v = queue[i];38        used[v] = true;39        for (auto to: internalEdges(v)) {40            if (!used[to]) {41                parents[to] = v;42                queue.push_back(to);43            }44        }45    }4647    for (auto& x: parents) {48        if (x != -1) {49            x = vertexLabel(x);50        }51    }5253    return parents;54}5556Tree& Tree::shuffle() {57    doShuffle();58    return *this;59}6061Tree Tree::shuffled() const {62    Tree t = *this;63    return t.shuffle();64}6566Tree& Tree::shuffleAllBut(const Array& except) {67    doShuffleAllBut(except);68    return *this;69}7071Tree Tree::shuffledAllBut(const Array& except) const {72    Tree g(*this);73    return g.shuffleAllBut(except);74}7576Tree Tree::link(int vInThis, const Tree& other, int vInOther) {77    ensure(vInThis < n(), "Cannot link a nonexistent vertex");78    ensure(vInOther < other.n(), "Cannot link to a nonexistent vertex");7980    Tree t(*this);8182    for (const auto& e: other.edges()) {83        t.addEdge(e.first + n(), e.second + n());84    }8586    t.addEdge(vInThis, vInOther + n());8788    return t;89}9091Tree Tree::glue(int vInThis, const Tree& other, int vInOther) {92    ensure(vInThis < n(), "Cannot glue a nonexistent vertex");93    ensure(vInOther < other.n(), "Cannot glue to a nonexistent vertex");9495    auto newLabel = [vInThis, vInOther, &other, this] (int v) {96        if (v < vInOther) {97            return n() + v;98        } else if (v == vInOther) {99            return vInThis;100        } else {101            return n() + v - 1;102        }103    };104105    Tree t(*this);106107    for (const auto& e: other.edges()) {108        t.addEdge(newLabel(e.first), newLabel(e.second));109    }110111    ensure(t.n() == n() + other.n() - 1);112113    return t;114}115116// Tree generators go here117118Tree Tree::bamboo(int size) {119    ensure(size > 0, "Number of vertices in the tree must be positive");120    checkLargeParameter(size);121    Tree t;122    for (int i = 0; i + 1 < size; ++i) {123        t.addEdge(i, i+1);124    }125    t.normalizeEdges();126    return t;127}128129Tree Tree::random(int size) {130    ensure(size > 0, "Number of vertices in the tree must be positive");131    checkLargeParameter(size);132    if (size == 1) {133        return Tree();134    }135    return fromPruferSequence(Array::random(size - 2, size));136}137138Tree Tree::randomPrim(int size, int elongation) {139    ensure(size > 0, "Number of vertices in the tree must be positive");140    checkLargeParameter(size);141    Tree t;142    for (int v = 1; v < size; ++v) {143        int parent = rnd.wnext(v, elongation);144        t.addEdge(parent, v);145    }146    t.normalizeEdges();147    return t;148}149150Tree Tree::randomKruskal(int size) {151    ensure(size > 0, "Number of vertices in the tree must be positive");152    checkLargeParameter(size);153    Tree t;154    t.extend(size);155    while (!t.isConnected()) {156        auto e = rnd.nextp(size, dpair);157        if (t.canAddEdge(e.first, e.second)) {158            t.addEdge(e.first, e.second);159        }160    }161    return t;162}163164Tree Tree::star(int size) {165    ensure(size > 0, "Number of vertices in the tree must be positive");166    checkLargeParameter(size);167    Tree t;168    for (int i = 1; i < size; ++i) {169        t.addEdge(0, i);170    }171    t.normalizeEdges();172    return t;173}174175Tree Tree::caterpillar(int size, int length) {176    ensure(size > 0, "Number of vertices in the tree must be positive");177    ensure(length > 0, "Length of the caterpillar must be positive");178    checkLargeParameter(size);179    ensure(length <= size);180    Tree t = Tree::bamboo(length);181    for (int i = length; i < size; ++i) {182        t.addEdge(rnd.next(length), i);183    }184    t.normalizeEdges();185    return t;186}187188Tree Tree::binary(int size) {189    return kary(size, 2);190}191192Tree Tree::kary(int size, int k) {193    ensure(size > 0, "Number of vertices in the tree must be positive");194    checkLargeParameter(size);195196    Tree t;197    for (int i = 1; i < size; ++i) {198        t.addEdge((i - 1) / k, i);199    }200    t.normalizeEdges();201    return t;202}203204Tree Tree::fromPruferSequence(const Array& code) {205    std::vector<int> degree(code.size() + 2, 1);206    for (int v: code) {207        ++degree[v];208    }209210    std::set<int> leaves;211    for (size_t v = 0; v != degree.size(); ++v) {212        if (degree[v] == 1) {213            leaves.insert(v);214        }215    }216217    Tree t;218    for (int v: code) {219        ENSURE(!leaves.empty());220        int to = *leaves.begin();221        leaves.erase(leaves.begin());222        if (--degree[v] == 1) {223            leaves.insert(v);224        }225226        t.addEdge(v, to);227    }228229    ENSURE(leaves.size() == 2u);230    t.addEdge(*leaves.begin(), *leaves.rbegin());231    t.normalizeEdges();232    return t;233234}235236void Tree::doPrintParents(std::ostream& out, const OutputModifier& mod) const {237    int root = mod.printParents;238    if (root == -1) {239        root = 0;240    }241242    auto parents = this->parents(root);243    if (mod.printParents == -1) {244        parents.erase(parents.begin());245    }246247    if (mod.printN) {248        out << n() << "\n";249    }250251    // TODO: avoid copy-paste from doPrintEdges252    if (mod.printWeights && vertexWeights_.hasNonEmpty()) {253        auto vertexWeights = prepareWeightArray(vertexWeights_, n());254        for (int i = 0; i < n(); ++i) {255            if (i > 0) {256                out << " ";257            }258            JNGEN_PRINT_NO_MOD(vertexWeights[vertexByLabel(i)]);259        }260        out << "\n";261    }262263    auto t(mod);264    {265        auto mod(t);266        mod.printN = false;267268        if (mod.printWeights && edgeWeights_.hasNonEmpty()) {269            ensure(false, "Printing parents and edge weights is not supported");270            ensure(271                mod.printParents == -1,272                "Root must not be set to any exact value when printing a tree "273                "with edge weights. To fix it, either set printParents() "274                "or printWeights(false)");275            ENSURE(root == 0);276            // TODO: some code to be here277        } else {278            JNGEN_PRINT(parents);279        }280    }281}282