// File: sebastienmeyer2[P]mst-clustering/src/mst_algorithm.cpp
// Function: MSTAlgorithm::compute_clustering(int)
std::unordered_map<Node*, Node*> MSTAlgorithm::compute_clustering(int k)
{
    /*!
     * @brief Creates a mapping between nodes of the MST (and initial) graph 
     * after it is built, and their representatives where we have eliminated 
     * the k-1 most expansive edges from the MST graph. 
     * 
     * @param k The number of clusters to build 
     * 
     * @return A mapping between nodes of the graph(s) and their representatives 
     * after removing k-1 edges
     * 
     */

    if (!this->treated) {
        this->compute_mst();
    }

    int n = this->mst_graph.get_number_of_nodes();
    assert(("There are less points than clusters!", k <= n));

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

            if (w1 < w2) {
                return false;
            } else if (w1 > w2) {
                return true;
            } else { // Allows multiple keys for same weight values
                intptr_t p1 = reinterpret_cast<intptr_t>(e1);
                intptr_t p2 = reinterpret_cast<intptr_t>(e2);

                return p1 < p2;
            }
        };

    // builds an ordered queue of the edges of the MST graph
    std::unordered_set<Edge*> mst_edges = this->mst_graph.get_edges();

    std::priority_queue<Edge*, std::vector<Edge*>, decltype(cmp)> pq(cmp);

    for (Edge* e : mst_edges) {
        pq.push(e);
    }

    // selects only the E-(k-1) lightest edges of the MST graph
    std::vector<Node*> nodes = this->mst_graph.get_nodes();
    UnionFind uf = UnionFind(nodes);

    int nb_edges = (n-1) - (k-1); // MST is a tree 

    for (int i = 0; i < nb_edges; i ++) {
        Edge* min_edge = pq.top();
        uf.Union(min_edge->p1, min_edge->p2);
        pq.pop();
    }

    // builds a map from all the nodes to their representatives 
    std::unordered_map<Node*, Node*> clusters;

    for (Node* node : nodes) {
        Node* rep = uf.Find(node);

        clusters.insert(std::pair<Node*, Node*>(node, rep));
    }

    return clusters;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x240, %rsp            # imm = 0x240
movq %rdi, -0x218(%rbp)
movq %rdi, %rax
movq %rax, -0x210(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x208(%rbp)
testb $0x1, 0x100(%rax)
jne 0x26627
movq -0x208(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
movq -0x208(%rbp), %rdi
addq $0x10, %rdi
callq 0xd510
movl %eax, -0x18(%rbp)
movl -0x14(%rbp), %eax
cmpl -0x18(%rbp), %eax
jg 0x26644
jmp 0x26663
leaq 0x1118a(%rip), %rdi     # 0x377d5
leaq 0x111b4(%rip), %rsi     # 0x37806
movl $0x5e, %edx
leaq 0x111be(%rip), %rcx     # 0x3781c
callq 0xa4a0
movq -0x208(%rbp), %rsi
addq $0x10, %rsi
leaq -0x58(%rbp), %rdi
callq 0xd660
xorps %xmm0, %xmm0
movaps %xmm0, -0x90(%rbp)
movq $0x0, -0x80(%rbp)
leaq -0x90(%rbp), %rdi
movq %rdi, -0x220(%rbp)
callq 0x278c0
movq -0x220(%rbp), %rdx
leaq -0x78(%rbp), %rdi
leaq -0x19(%rbp), %rsi
callq 0x26a60
jmp 0x266b2
leaq -0x90(%rbp), %rdi
callq 0x278e0
leaq -0x58(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rdi
callq 0xe520
movq %rax, -0xb0(%rbp)
movq -0xa8(%rbp), %rdi
callq 0xe550
movq %rax, -0xb8(%rbp)
leaq -0xb0(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0xe580
testb $0x1, %al
jne 0x26708
jmp 0x2677a
leaq -0xb0(%rbp), %rdi
callq 0xe5b0
movq (%rax), %rax
movq %rax, -0xc0(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x26ae0
jmp 0x26730
jmp 0x26732
leaq -0xb0(%rbp), %rdi
callq 0xe5e0
jmp 0x266ef
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x278e0
jmp 0x26a4a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x26a41
movq -0x208(%rbp), %rsi
addq $0x10, %rsi
leaq -0xd8(%rbp), %rdi
callq 0xd530
jmp 0x26793
leaq -0x1a0(%rbp), %rdi
leaq -0xd8(%rbp), %rsi
callq 0x27940
jmp 0x267a8
leaq -0x188(%rbp), %rdi
leaq -0x1a0(%rbp), %rsi
callq 0x30fd0
jmp 0x267bd
leaq -0x1a0(%rbp), %rdi
callq 0xded0
movl -0x18(%rbp), %eax
subl $0x1, %eax
movl -0x14(%rbp), %ecx
subl $0x1, %ecx
subl %ecx, %eax
movl %eax, -0x1a4(%rbp)
movl $0x0, -0x1a8(%rbp)
movl -0x1a8(%rbp), %eax
cmpl -0x1a4(%rbp), %eax
jge 0x268a7
leaq -0x78(%rbp), %rdi
callq 0x26b30
movq %rax, -0x228(%rbp)
jmp 0x2680b
movq -0x228(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x1b0(%rbp)
movq -0x1b0(%rbp), %rax
movq (%rax), %rsi
movq 0x8(%rax), %rdx
leaq -0x188(%rbp), %rdi
callq 0x31410
jmp 0x26838
leaq -0x78(%rbp), %rdi
callq 0x26b50
jmp 0x26843
jmp 0x26845
movl -0x1a8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1a8(%rbp)
jmp 0x267e7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x26a35
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x1a0(%rbp), %rdi
callq 0xded0
jmp 0x26a35
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x26a29
movq -0x218(%rbp), %rdi
movb $0x0, -0x1b1(%rbp)
callq 0x27a30
leaq -0xd8(%rbp), %rax
movq %rax, -0x1c0(%rbp)
movq -0x1c0(%rbp), %rdi
callq 0x15bd0
movq %rax, -0x1c8(%rbp)
movq -0x1c0(%rbp), %rdi
callq 0x15a20
movq %rax, -0x1d0(%rbp)
leaq -0x1c8(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x27a50
testb $0x1, %al
jne 0x2690a
jmp 0x269d3
leaq -0x1c8(%rbp), %rdi
callq 0x15fb0
movq (%rax), %rax
movq %rax, -0x1d8(%rbp)
movq -0x1d8(%rbp), %rsi
leaq -0x188(%rbp), %rdi
callq 0x31360
movq %rax, -0x230(%rbp)
jmp 0x2693c
movq -0x230(%rbp), %rax
movq %rax, -0x1e0(%rbp)
leaq -0x1f0(%rbp), %rdi
leaq -0x1d8(%rbp), %rsi
leaq -0x1e0(%rbp), %rdx
callq 0x27ad0
jmp 0x26966
movq -0x218(%rbp), %rdi
leaq -0x1f0(%rbp), %rsi
callq 0x27a90
movb %dl, -0x239(%rbp)
movq %rax, -0x238(%rbp)
jmp 0x26988
movb -0x239(%rbp), %al
movq -0x238(%rbp), %rcx
movq %rcx, -0x200(%rbp)
movb %al, -0x1f8(%rbp)
leaq -0x1c8(%rbp), %rdi
callq 0x27b00
jmp 0x268ee
movq -0x218(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
callq 0x1be30
jmp 0x26a29
movb $0x1, -0x1b1(%rbp)
testb $0x1, -0x1b1(%rbp)
jne 0x269ef
movq -0x218(%rbp), %rdi
callq 0x1be30
leaq -0x188(%rbp), %rdi
callq 0x311e0
leaq -0xd8(%rbp), %rdi
callq 0xded0
leaq -0x78(%rbp), %rdi
callq 0x26ba0
leaq -0x58(%rbp), %rdi
callq 0xdf50
movq -0x210(%rbp), %rax
addq $0x240, %rsp            # imm = 0x240
popq %rbp
retq
leaq -0x188(%rbp), %rdi
callq 0x311e0
leaq -0xd8(%rbp), %rdi
callq 0xded0
leaq -0x78(%rbp), %rdi
callq 0x26ba0
leaq -0x58(%rbp), %rdi
callq 0xdf50
movq -0x98(%rbp), %rdi
callq 0xade0
nop