// File: sebastienmeyer2[P]mst-clustering/src/mst_kruskal.cpp
// Function: KruskalAlgorithm::compute_mst()
void KruskalAlgorithm::compute_mst()
{
    /*!
     * @brief Computes the Minimum Spanning Tree of the graph associated to 
     * this instance of MSTAlgorithm, using Kruskal's algorithm. More specifically,
     * sorts all the edges by their weight, and uses an Union-Find data structure
     * to select which components to union at each iteration, until there is 
     * only one left, which is the MST.
     * 
     */

    this->mst_weight = 0.0;
    std::cout << "\nComputing the MST using Kruskal's algorithm...";
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    int n = this->initial_graph->get_number_of_nodes();
    std::vector<Node*> nodes = this->initial_graph->get_nodes();
    std::unordered_set<Edge*> edges = this->initial_graph->get_edges();

    auto cmp = [](const Edge* e1, const Edge* e2) 
        { 
            double w1 = e1->weight;
            double w2 = e2->weight;

            if (w1 < w2) {
                return false; // reversed in order to follow priority queue's implementation
            } else if (w1 > w2) {
                return true;
            } else { // allows multiple keys for same weight values (arbitrary comp)
                intptr_t p1 = reinterpret_cast<intptr_t>(e1);
                intptr_t p2 = reinterpret_cast<intptr_t>(e2);

                return p1 < p2;
            }
        };

    // initialization of the algorithm
    std::priority_queue<Edge*, std::vector<Edge*>, decltype(cmp)> pq(cmp);
    for (Edge* e : edges) {
        pq.push(e);
    }

    UnionFind uf = UnionFind(nodes);

    // while there is more than one component, we add edges that are shared 
    int k = uf.get_num_classes();
    while (k > 1) {

        Edge* min_edge = pq.top();
        pq.pop();

        Node* rep1 = uf.Find(min_edge->p1);
        Node* rep2 = uf.Find(min_edge->p2);

        if (rep1 != rep2) {
            this->mst_graph.add_edge(min_edge);
            this->mst_weight += min_edge->weight;
            uf.Union(rep1, rep2);
        }

        k = uf.get_num_classes();
    }

    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::cout << "[OK]" << std::endl;
    this->treatment_done();

    std::cout << "Total weight of the MST: " << this->mst_weight << std::endl;

    std::cout << "Time spent by the algorithm: " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << " µs" << std::endl;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x250, %rsp            # imm = 0x250
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x1d8(%rbp)
movq $0x0, 0xf8(%rax)
movq 0x21a04(%rip), %rdi     # 0x4ffb0
leaq 0x9386(%rip), %rsi      # 0x37939
callq 0xa780
callq 0xaa70
movq %rax, %rcx
movq -0x1d8(%rbp), %rax
movq %rcx, -0x10(%rbp)
movq 0x8(%rax), %rdi
callq 0xd510
movl %eax, %ecx
movq -0x1d8(%rbp), %rax
movl %ecx, -0x14(%rbp)
movq 0x8(%rax), %rsi
leaq -0x30(%rbp), %rdi
callq 0xd530
movq -0x1d8(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x68(%rbp), %rdi
callq 0xd660
jmp 0x2e603
xorps %xmm0, %xmm0
movaps %xmm0, -0xb0(%rbp)
movq $0x0, -0xa0(%rbp)
leaq -0xb0(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
callq 0x278c0
movq -0x1e0(%rbp), %rdx
leaq -0x98(%rbp), %rdi
leaq -0x75(%rbp), %rsi
callq 0x2eaa0
jmp 0x2e644
leaq -0xb0(%rbp), %rdi
callq 0x278e0
leaq -0x68(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rdi
callq 0xe520
movq %rax, -0xc0(%rbp)
movq -0xb8(%rbp), %rdi
callq 0xe550
movq %rax, -0xc8(%rbp)
leaq -0xc0(%rbp), %rdi
leaq -0xc8(%rbp), %rsi
callq 0xe580
testb $0x1, %al
jne 0x2e69a
jmp 0x2e714
leaq -0xc0(%rbp), %rdi
callq 0xe5b0
movq (%rax), %rax
movq %rax, -0xd0(%rbp)
leaq -0x98(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0x2eb20
jmp 0x2e6c5
jmp 0x2e6c7
leaq -0xc0(%rbp), %rdi
callq 0xe5e0
jmp 0x2e681
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x2ea84
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0xb0(%rbp), %rdi
callq 0x278e0
jmp 0x2ea7b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
jmp 0x2ea6f
leaq -0x198(%rbp), %rdi
leaq -0x30(%rbp), %rsi
callq 0x27940
jmp 0x2e726
leaq -0x180(%rbp), %rdi
leaq -0x198(%rbp), %rsi
callq 0x30fd0
jmp 0x2e73b
leaq -0x198(%rbp), %rdi
callq 0xded0
leaq -0x180(%rbp), %rdi
callq 0x31340
movl %eax, -0x1e4(%rbp)
jmp 0x2e75b
movl -0x1e4(%rbp), %eax
movl %eax, -0x19c(%rbp)
cmpl $0x1, -0x19c(%rbp)
jle 0x2e8d4
leaq -0x98(%rbp), %rdi
callq 0x2eb70
movq %rax, -0x1f0(%rbp)
jmp 0x2e789
movq -0x1f0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x1a8(%rbp)
leaq -0x98(%rbp), %rdi
callq 0x2eb90
jmp 0x2e7a8
movq -0x1a8(%rbp), %rax
movq (%rax), %rsi
leaq -0x180(%rbp), %rdi
callq 0x31360
movq %rax, -0x1f8(%rbp)
jmp 0x2e7c7
movq -0x1f8(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movq -0x1a8(%rbp), %rax
movq 0x8(%rax), %rsi
leaq -0x180(%rbp), %rdi
callq 0x31360
movq %rax, -0x200(%rbp)
jmp 0x2e7f5
movq -0x200(%rbp), %rax
movq %rax, -0x1b8(%rbp)
movq -0x1b0(%rbp), %rax
cmpq -0x1b8(%rbp), %rax
je 0x2e8af
movq -0x1d8(%rbp), %rdi
addq $0x10, %rdi
movq -0x1a8(%rbp), %rsi
callq 0xcef0
jmp 0x2e830
movq -0x1d8(%rbp), %rax
movq -0x1a8(%rbp), %rcx
movsd 0x10(%rcx), %xmm1
movsd 0xf8(%rax), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xf8(%rax)
movq -0x1b0(%rbp), %rsi
movq -0x1b8(%rbp), %rdx
leaq -0x180(%rbp), %rdi
callq 0x31410
jmp 0x2e873
jmp 0x2e8af
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x198(%rbp), %rdi
callq 0xded0
jmp 0x2ea6f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
leaq -0x180(%rbp), %rdi
callq 0x311e0
jmp 0x2ea6f
leaq -0x180(%rbp), %rdi
callq 0x31340
movl %eax, -0x204(%rbp)
jmp 0x2e8c3
movl -0x204(%rbp), %eax
movl %eax, -0x19c(%rbp)
jmp 0x2e767
callq 0xaa70
movq %rax, -0x1c0(%rbp)
movq 0x216c9(%rip), %rdi     # 0x4ffb0
leaq 0x8fba(%rip), %rsi      # 0x378a8
callq 0xa780
movq %rax, -0x210(%rbp)
jmp 0x2e8fc
movq -0x210(%rbp), %rdi
movq 0x2167e(%rip), %rsi     # 0x4ff88
callq 0xa7e0
jmp 0x2e911
movq -0x1d8(%rbp), %rdi
callq 0x265c0
jmp 0x2e91f
movq 0x2168a(%rip), %rdi     # 0x4ffb0
leaq 0x8f80(%rip), %rsi      # 0x378ad
callq 0xa780
movq %rax, -0x218(%rbp)
jmp 0x2e93b
movq -0x218(%rbp), %rdi
movq -0x1d8(%rbp), %rax
movsd 0xf8(%rax), %xmm0
callq 0xaee0
movq %rax, -0x220(%rbp)
jmp 0x2e95f
movq -0x220(%rbp), %rdi
movq 0x2161b(%rip), %rsi     # 0x4ff88
callq 0xa7e0
jmp 0x2e974
movq 0x21635(%rip), %rdi     # 0x4ffb0
leaq 0x8f45(%rip), %rsi      # 0x378c7
callq 0xa780
movq %rax, -0x228(%rbp)
jmp 0x2e990
leaq -0x1c0(%rbp), %rdi
leaq -0x10(%rbp), %rsi
callq 0x2b6a0
movq %rax, -0x230(%rbp)
jmp 0x2e9a9
movq -0x230(%rbp), %rax
movq %rax, -0x1d0(%rbp)
leaq -0x1d0(%rbp), %rdi
callq 0x2b670
movq %rax, -0x238(%rbp)
jmp 0x2e9cc
movq -0x238(%rbp), %rax
movq %rax, -0x1c8(%rbp)
leaq -0x1c8(%rbp), %rdi
callq 0x2b6f0
movq %rax, -0x240(%rbp)
jmp 0x2e9ef
movq -0x240(%rbp), %rsi
movq -0x228(%rbp), %rdi
callq 0xae50
movq %rax, -0x248(%rbp)
jmp 0x2ea0b
movq -0x248(%rbp), %rdi
leaq 0x8ecc(%rip), %rsi      # 0x378e5
callq 0xa780
movq %rax, -0x250(%rbp)
jmp 0x2ea27
movq -0x250(%rbp), %rdi
movq 0x21553(%rip), %rsi     # 0x4ff88
callq 0xa7e0
jmp 0x2ea3c
leaq -0x180(%rbp), %rdi
callq 0x311e0
leaq -0x98(%rbp), %rdi
callq 0x2ebe0
leaq -0x68(%rbp), %rdi
callq 0xdf50
leaq -0x30(%rbp), %rdi
callq 0xded0
addq $0x250, %rsp            # imm = 0x250
popq %rbp
retq
leaq -0x98(%rbp), %rdi
callq 0x2ebe0
leaq -0x68(%rbp), %rdi
callq 0xdf50
leaq -0x30(%rbp), %rdi
callq 0xded0
movq -0x70(%rbp), %rdi
callq 0xade0
nopw %cs:(%rax,%rax)