// File: sebastienmeyer2[P]mst-clustering/src/node.cpp
// Function: intracluster_variance(std::unordered_map<Node*, Node*, std::hash<Node*>, std::equal_to<Node*>, std::allocator<std::pair<Node* const, Node*>>>)
double intracluster_variance(std::unordered_map<Node*, Node*> clusters)
{
    /*!
     * @brief Returns the intracluster variance by computing the centers of 
     * the different clusters first 
     * 
     * @param clusters The different clusters computed, that is, a map between 
     * nodes and their representatives
     * 
     * @return The intracluster variance of these clusters
     * 
     */

    double intracluster_variance = 0.0;

    // firstly, we compute the clusters in the reverse mode, that is, 
    // we take for each representative, all its members
    std::unordered_set<Node*> representatives;
    std::unordered_map<Node*, std::unordered_set<Node*> > members;

    for (auto kv : clusters) {
        Node* node = kv.first;
        Node* rep = kv.second;

        representatives.insert(rep);
        
        if (members.find(rep) == members.end()) {
            members.insert(std::pair<Node*, std::unordered_set<Node*> >(rep, std::unordered_set<Node*>()));
        }

        members.at(rep).insert(node);
    }

    for (Node* rep : representatives) {
        int d = rep->get_point()->get_dim();
        int cluster_size = members.at(rep).size();

        // secondly, we compute centers as in the M-step of kmeans 
        Node* center = new Node(rep->label, new Point());

        for (Node* member : members.at(rep)) {
            for (int j = 0; j < d; j ++) {
                center->get_point()->coords[j] += member->get_point()->coords[j];
            }
        }

        for (int j = 0; j < d; j ++) {
            center->get_point()->coords[j] /= cluster_size;
        }

        // finally, we compute the intracluster variance out of these centers
        double cluster_variance = 0.0;
        for (Node* member : members.at(rep)) {
            cluster_variance += member->get_point()->distance(center->get_point());
        }

        intracluster_variance += cluster_variance;
    }
    intracluster_variance /= clusters.size();

    return intracluster_variance;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2c0, %rsp            # imm = 0x2C0
movq %rdi, -0x218(%rbp)
movq %rdi, -0x8(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x10(%rbp)
leaq -0x48(%rbp), %rdi
callq 0xdbe0
leaq -0x80(%rbp), %rdi
callq 0xd930
movq -0x218(%rbp), %rdi
movq %rdi, -0x88(%rbp)
movq -0x88(%rbp), %rdi
callq 0x1bb40
movq %rax, -0x90(%rbp)
movq -0x88(%rbp), %rdi
callq 0x1bb70
movq %rax, -0x98(%rbp)
leaq -0x90(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x1bba0
testb $0x1, %al
jne 0x23250
jmp 0x23473
leaq -0x90(%rbp), %rdi
callq 0x1bbd0
movups (%rax), %xmm0
movaps %xmm0, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0xc0(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0xdd40
movb %dl, -0x221(%rbp)
movq %rax, -0x220(%rbp)
jmp 0x232a1
movb -0x221(%rbp), %al
movq -0x220(%rbp), %rcx
movq %rcx, -0xe0(%rbp)
movb %al, -0xd8(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0xdb40
movq %rax, -0x230(%rbp)
jmp 0x232d4
movq -0x230(%rbp), %rax
movq %rax, -0xe8(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xdb70
movq %rax, -0xf0(%rbp)
leaq -0xe8(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0xdb10
testb $0x1, %al
jne 0x2330e
jmp 0x2340d
xorps %xmm0, %xmm0
movaps %xmm0, -0x150(%rbp)
movaps %xmm0, -0x160(%rbp)
movaps %xmm0, -0x170(%rbp)
movq $0x0, -0x140(%rbp)
leaq -0x170(%rbp), %rdi
movq %rdi, -0x238(%rbp)
callq 0xdbe0
movq -0x238(%rbp), %rdx
leaq -0x130(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0xdc00
jmp 0x23360
leaq -0x80(%rbp), %rdi
leaq -0x130(%rbp), %rsi
callq 0xdba0
movb %dl, -0x241(%rbp)
movq %rax, -0x240(%rbp)
jmp 0x2337f
movb -0x241(%rbp), %al
movq -0x240(%rbp), %rcx
movq %rcx, -0x180(%rbp)
movb %al, -0x178(%rbp)
leaq -0x130(%rbp), %rdi
callq 0xdc40
leaq -0x170(%rbp), %rdi
callq 0xdc60
jmp 0x2340d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
jmp 0x238ce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
jmp 0x233fc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
leaq -0x130(%rbp), %rdi
callq 0xdc40
leaq -0x170(%rbp), %rdi
callq 0xdc60
jmp 0x238ce
leaq -0x80(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0xdc80
movq %rax, -0x250(%rbp)
jmp 0x23426
movq -0x250(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0xdd40
movb %dl, -0x259(%rbp)
movq %rax, -0x258(%rbp)
jmp 0x23448
movb -0x259(%rbp), %al
movq -0x258(%rbp), %rcx
movq %rcx, -0x190(%rbp)
movb %al, -0x188(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x1bd30
jmp 0x23234
leaq -0x48(%rbp), %rax
movq %rax, -0x198(%rbp)
movq -0x198(%rbp), %rdi
callq 0x24690
movq %rax, -0x1a0(%rbp)
movq -0x198(%rbp), %rdi
callq 0xdd10
movq %rax, -0x1a8(%rbp)
leaq -0x1a0(%rbp), %rdi
leaq -0x1a8(%rbp), %rsi
callq 0x246c0
testb $0x1, %al
jne 0x234c0
jmp 0x2385d
leaq -0x1a0(%rbp), %rdi
callq 0x246f0
movq (%rax), %rax
movq %rax, -0x1b0(%rbp)
movq -0x1b0(%rbp), %rdi
callq 0x23100
movq %rax, %rdi
callq 0xb5c0
movl %eax, -0x260(%rbp)
jmp 0x234f2
movl -0x260(%rbp), %eax
movl %eax, -0x1b4(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x1b0(%rbp), %rsi
callq 0xdc80
movq %rax, -0x268(%rbp)
jmp 0x23517
movq -0x268(%rbp), %rdi
callq 0x24720
movl %eax, -0x1b8(%rbp)
movl $0x18, %edi
callq 0xa790
movq %rax, -0x270(%rbp)
jmp 0x2353c
movq -0x1b0(%rbp), %rax
movl 0x10(%rax), %eax
movl %eax, -0x27c(%rbp)
movl $0x10, %edi
callq 0xa790
movq %rax, -0x278(%rbp)
jmp 0x2355f
movq -0x278(%rbp), %rdi
callq 0xb520
jmp 0x2356d
movq -0x278(%rbp), %rdx
movl -0x27c(%rbp), %esi
movq -0x270(%rbp), %rdi
callq 0x230d0
jmp 0x23588
movq -0x270(%rbp), %rax
movq %rax, -0x1c0(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x1b0(%rbp), %rsi
callq 0xdc80
movq %rax, -0x288(%rbp)
jmp 0x235af
movq -0x288(%rbp), %rax
movq %rax, -0x1c8(%rbp)
movq -0x1c8(%rbp), %rdi
callq 0x24690
movq %rax, -0x1d0(%rbp)
movq -0x1c8(%rbp), %rdi
callq 0xdd10
movq %rax, -0x1d8(%rbp)
leaq -0x1d0(%rbp), %rdi
leaq -0x1d8(%rbp), %rsi
callq 0x246c0
testb $0x1, %al
jne 0x235ff
jmp 0x236ed
leaq -0x1d0(%rbp), %rdi
callq 0x246f0
movq (%rax), %rax
movq %rax, -0x1e0(%rbp)
movl $0x0, -0x1e4(%rbp)
movl -0x1e4(%rbp), %eax
cmpl -0x1b4(%rbp), %eax
jge 0x236da
movq -0x1e0(%rbp), %rdi
callq 0x23100
movq (%rax), %rax
movslq -0x1e4(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, -0x290(%rbp)
movq -0x1c0(%rbp), %rdi
callq 0x23100
movsd -0x290(%rbp), %xmm0
movq (%rax), %rax
movslq -0x1e4(%rbp), %rcx
addsd (%rax,%rcx,8), %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x1e4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1e4(%rbp)
jmp 0x2361f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
jmp 0x236c4
movq -0x278(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xc8(%rbp)
movl %eax, -0xcc(%rbp)
movl $0x10, %esi
callq 0xa7b0
movq -0x270(%rbp), %rdi
movl $0x18, %esi
callq 0xa7b0
jmp 0x238ce
jmp 0x236dc
leaq -0x1d0(%rbp), %rdi
callq 0x24740
jmp 0x235e3
movl $0x0, -0x1e8(%rbp)
movl -0x1e8(%rbp), %eax
cmpl -0x1b4(%rbp), %eax
jge 0x23752
cvtsi2sdl -0x1b8(%rbp), %xmm0
movsd %xmm0, -0x298(%rbp)
movq -0x1c0(%rbp), %rdi
callq 0x23100
movsd -0x298(%rbp), %xmm1
movq (%rax), %rax
movslq -0x1e8(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, (%rax,%rcx,8)
movl -0x1e8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1e8(%rbp)
jmp 0x236f7
movq $0x0, -0x1f0(%rbp)
leaq -0x80(%rbp), %rdi
leaq -0x1b0(%rbp), %rsi
callq 0xdc80
movq %rax, -0x2a0(%rbp)
jmp 0x23776
movq -0x2a0(%rbp), %rax
movq %rax, -0x1f8(%rbp)
movq -0x1f8(%rbp), %rdi
callq 0x24690
movq %rax, -0x200(%rbp)
movq -0x1f8(%rbp), %rdi
callq 0xdd10
movq %rax, -0x208(%rbp)
leaq -0x200(%rbp), %rdi
leaq -0x208(%rbp), %rsi
callq 0x246c0
testb $0x1, %al
jne 0x237c3
jmp 0x2383a
leaq -0x200(%rbp), %rdi
callq 0x246f0
movq (%rax), %rax
movq %rax, -0x210(%rbp)
movq -0x210(%rbp), %rdi
callq 0x23100
movq %rax, -0x2b0(%rbp)
movq -0x1c0(%rbp), %rdi
callq 0x23100
movq -0x2b0(%rbp), %rdi
movq %rax, %rsi
callq 0xb660
movsd %xmm0, -0x2a8(%rbp)
jmp 0x23811
movsd -0x2a8(%rbp), %xmm0
addsd -0x1f0(%rbp), %xmm0
movsd %xmm0, -0x1f0(%rbp)
leaq -0x200(%rbp), %rdi
callq 0x24740
jmp 0x237aa
movsd -0x1f0(%rbp), %xmm0
addsd -0x10(%rbp), %xmm0
movsd %xmm0, -0x10(%rbp)
leaq -0x1a0(%rbp), %rdi
callq 0x24740
jmp 0x234a4
movq -0x218(%rbp), %rdi
callq 0x24770
movq %rax, %xmm1
movaps 0x1385b(%rip), %xmm0    # 0x370d0
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movapd 0x1385f(%rip), %xmm0    # 0x370e0
subpd %xmm0, %xmm1
movaps %xmm1, %xmm0
unpckhpd %xmm1, %xmm1            # xmm1 = xmm1[1,1]
addsd %xmm0, %xmm1
movsd -0x10(%rbp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, -0x10(%rbp)
movsd -0x10(%rbp), %xmm0
movsd %xmm0, -0x2b8(%rbp)
leaq -0x80(%rbp), %rdi
callq 0xddb0
leaq -0x48(%rbp), %rdi
callq 0xdc60
movsd -0x2b8(%rbp), %xmm0
addq $0x2c0, %rsp            # imm = 0x2C0
popq %rbp
retq
leaq -0x80(%rbp), %rdi
callq 0xddb0
leaq -0x48(%rbp), %rdi
callq 0xdc60
movq -0xc8(%rbp), %rdi
callq 0xade0
nopl (%rax)