// File: Manca[P]algorithms2/./assignment2.hpp
// Function: assignment2::clustering_big::run_algorithm(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)
void run_algorithm(const std::string& inputFile)
        {
            std::fstream file(inputFile, std::ios::in);
            if (file.is_open())
            {
                PROFILE("Read input Clustering Big (slower algo)")
                int n, bpn;
                file >> n >> bpn;

                std::string node;
                std::getline(file, node);
                HashMap mapa;

                const int MAX_NODES = (int)std::pow(2, bpn);
                DataStructures::UnionFind uf(MAX_NODES); // total number of elements (2^24)

                while (std::getline(file, node))
                {
                    node.erase(std::remove_if(node.begin(), node.end(), [](char x) {return std::isspace(x); }), end(node));
                    std::bitset<24> bit_node(node);
                    int nodeNumber = bit_node.to_ulong();

                    mapa[nodeNumber] = false;
                }
                file.close();
                PROFILE_STOP();

                // generate distances
                std::vector<int> distances_one = generateHammingDistances(bpn, 1);
                std::vector<int> distances_two = generateHammingDistances(bpn, 2);
                int num_edg_cost_one = 0;
                int num_edg_cost_two = 0;

                PROFILE("Clustering big (slower algo)")
                // iterate through the map and find the neighbors
                for (auto& el : mapa)
                {
                    el.second = true;           // we won't bother to add already seen edge to UnionFind

                    for (auto d : distances_one)
                    {
                        int res = el.first ^ d;
                        auto exists = mapa.find(res);
                        if (exists != mapa.end() && !exists->second) // if it's found but not yet seen!
                        {
                            // add to UF (there is an edge from current element to the one 1 Hamming distance away)
                            num_edg_cost_one++;
                            uf.Union(exists->first, el.first);
                        }
                    }
                    for (auto d : distances_two)
                    {
                        int res = el.first ^ d;
                        auto exists = mapa.find(res);
                        if (exists != mapa.end() && !exists->second)
                        {
                            // add node connected to current one 2 Hamming distances away
                            num_edg_cost_two++;
                            uf.Union(exists->first, el.first);
                        }
                    }
                }
                PROFILE_STOP();
                // from total number of nodes (all clusters)
                // subtract leaders (clusters with nodes that are at most 2 Hamming distances away from each other)
                // and duplicated nodes to get number of clusters that are at least 3 Hamming distances away from others
                size_t totalNumberClusters = n - (MAX_NODES - uf.count()) - (n - mapa.size());
                std::cout << "Edges 1 Hamming distance away: " << num_edg_cost_one << std::endl;
                std::cout << "Edges 2 Hamming distances away: " << num_edg_cost_two << std::endl;
                std::cout << "Number of clusters: " << totalNumberClusters << std::endl;
                assert(totalNumberClusters == 6118);
            }
        }

// Assembly:
subq $0x518, %rsp            # imm = 0x518
movq %rdi, 0x510(%rsp)
movq 0x510(%rsp), %rsi
leaq 0x300(%rsp), %rdi
movq %rdi, 0x100(%rsp)
movl $0x8, %edx
callq 0x3410
movq 0x100(%rsp), %rdi
callq 0x3430
movb %al, 0x10f(%rsp)
jmp 0x5be7
movb 0x10f(%rsp), %al
testb $0x1, %al
jne 0x5bf7
jmp 0x662f
callq 0x10a60
movq %rax, 0xf8(%rsp)
jmp 0x5c06
leaq 0x2cf(%rsp), %rdi
movq %rdi, 0xf0(%rsp)
callq 0x3470
movq 0xf0(%rsp), %rdx
leaq 0x2a721(%rip), %rsi     # 0x3034b
leaq 0x2d0(%rsp), %rdi
callq 0x3360
jmp 0x5c39
movq 0xf8(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
callq 0x10ad0
jmp 0x5c50
leaq 0x2d0(%rsp), %rdi
callq 0x31f0
leaq 0x2cf(%rsp), %rdi
callq 0x3300
leaq 0x300(%rsp), %rdi
leaq 0x2c8(%rsp), %rsi
callq 0x31e0
movq %rax, 0xe8(%rsp)
jmp 0x5c89
movq 0xe8(%rsp), %rdi
leaq 0x2c4(%rsp), %rsi
callq 0x31e0
jmp 0x5ca0
leaq 0x2a0(%rsp), %rdi
movq %rdi, 0xe0(%rsp)
callq 0x3370
movq 0xe0(%rsp), %rsi
leaq 0x300(%rsp), %rdi
callq 0x3080
jmp 0x5ccc
leaq 0x268(%rsp), %rdi
callq 0x10fe0
movl 0x2c4(%rsp), %esi
movl $0x2, %edi
callq 0x10ff0
movsd %xmm0, 0xd8(%rsp)
jmp 0x5cf5
movsd 0xd8(%rsp), %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0x264(%rsp)
movl 0x264(%rsp), %esi
leaq 0x248(%rsp), %rdi
callq 0x10ca0
jmp 0x5d1f
jmp 0x5d21
leaq 0x300(%rsp), %rdi
leaq 0x2a0(%rsp), %rsi
callq 0x3080
movq %rax, 0xd0(%rsp)
jmp 0x5d40
movq 0xd0(%rsp), %rdi
movq (%rdi), %rax
movq -0x18(%rax), %rax
addq %rax, %rdi
callq 0x3310
movb %al, 0xcf(%rsp)
jmp 0x5d60
movb 0xcf(%rsp), %al
testb $0x1, %al
jne 0x5d70
jmp 0x5f76
leaq 0x2a0(%rsp), %rdi
movq %rdi, 0xb8(%rsp)
callq 0x3280
movq 0xb8(%rsp), %rdi
movq %rax, 0x230(%rsp)
callq 0x31b0
movq %rax, 0x228(%rsp)
movq 0x230(%rsp), %rdi
movq 0x228(%rsp), %rsi
callq 0x6660
movq %rax, 0xc0(%rsp)
jmp 0x5dc1
movq 0xc0(%rsp), %rax
movq %rax, 0x238(%rsp)
leaq 0x240(%rsp), %rdi
leaq 0x238(%rsp), %rsi
callq 0x11010
leaq 0x2a0(%rsp), %rdi
callq 0x11050
movq %rax, 0xb0(%rsp)
jmp 0x5dfd
movq 0xb0(%rsp), %rax
movq %rax, 0x210(%rsp)
leaq 0x218(%rsp), %rdi
leaq 0x210(%rsp), %rsi
callq 0x11010
movq 0x240(%rsp), %rsi
movq 0x218(%rsp), %rdx
leaq 0x2a0(%rsp), %rdi
callq 0x30b0
movq %rax, 0xa8(%rsp)
jmp 0x5e49
movq 0xa8(%rsp), %rax
movq %rax, 0x208(%rsp)
xorl %eax, %eax
movl %eax, %edx
leaq 0x200(%rsp), %rdi
leaq 0x2a0(%rsp), %rsi
callq 0x11080
jmp 0x5e74
leaq 0x200(%rsp), %rdi
callq 0x110f0
movq %rax, 0xa0(%rsp)
jmp 0x5e8b
movq 0xa0(%rsp), %rax
movl %eax, 0x1fc(%rsp)
leaq 0x268(%rsp), %rdi
leaq 0x1fc(%rsp), %rsi
callq 0x11100
movq %rax, 0x98(%rsp)
jmp 0x5eb9
movq 0x98(%rsp), %rax
movb $0x0, (%rax)
jmp 0x5d21
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x6644
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x5f19
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
leaq 0x2d0(%rsp), %rdi
callq 0x31f0
leaq 0x2cf(%rsp), %rdi
callq 0x3300
jmp 0x6644
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x6620
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x6613
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x6606
leaq 0x300(%rsp), %rdi
callq 0x3040
jmp 0x5f85
callq 0x10a60
movq %rax, 0x90(%rsp)
jmp 0x5f94
movq 0x90(%rsp), %rdi
callq 0x10b90
jmp 0x5fa3
movl 0x2c4(%rsp), %esi
leaq 0x1e0(%rsp), %rdi
movl $0x1, %edx
callq 0x5a50
jmp 0x5fbe
movl 0x2c4(%rsp), %esi
leaq 0x1c8(%rsp), %rdi
movl $0x2, %edx
callq 0x5a50
jmp 0x5fd9
movl $0x0, 0x1c4(%rsp)
movl $0x0, 0x1c0(%rsp)
callq 0x10a60
movq %rax, 0x88(%rsp)
jmp 0x5ffe
leaq 0x19f(%rsp), %rdi
movq %rdi, 0x80(%rsp)
callq 0x3470
movq 0x80(%rsp), %rdx
leaq 0x2a351(%rip), %rsi     # 0x30373
leaq 0x1a0(%rsp), %rdi
callq 0x3360
jmp 0x6031
movq 0x88(%rsp), %rdi
leaq 0x1a0(%rsp), %rsi
callq 0x10ad0
jmp 0x6048
leaq 0x1a0(%rsp), %rdi
callq 0x31f0
leaq 0x19f(%rsp), %rdi
callq 0x3300
leaq 0x268(%rsp), %rax
movq %rax, 0x190(%rsp)
movq 0x190(%rsp), %rdi
callq 0x11130
movq %rax, 0x188(%rsp)
movq 0x190(%rsp), %rdi
callq 0x11160
movq %rax, 0x180(%rsp)
leaq 0x188(%rsp), %rdi
leaq 0x180(%rsp), %rsi
callq 0x11190
testb $0x1, %al
jne 0x60ba
jmp 0x641d
leaq 0x188(%rsp), %rdi
callq 0x111b0
movq %rax, 0x178(%rsp)
movq 0x178(%rsp), %rax
movb $0x1, 0x4(%rax)
leaq 0x1e0(%rsp), %rax
movq %rax, 0x170(%rsp)
movq 0x170(%rsp), %rdi
callq 0x102f0
movq %rax, 0x168(%rsp)
movq 0x170(%rsp), %rdi
callq 0x10320
movq %rax, 0x160(%rsp)
leaq 0x168(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x10350
testb $0x1, %al
jne 0x6133
jmp 0x62b1
leaq 0x168(%rsp), %rdi
callq 0x10390
movl (%rax), %eax
movl %eax, 0x15c(%rsp)
movq 0x178(%rsp), %rax
movl (%rax), %eax
movl 0x15c(%rsp), %ecx
xorl %ecx, %eax
movl %eax, 0x158(%rsp)
leaq 0x268(%rsp), %rdi
leaq 0x158(%rsp), %rsi
callq 0x111d0
movq %rax, 0x78(%rsp)
jmp 0x617f
movq 0x78(%rsp), %rax
movq %rax, 0x150(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x11160
movq %rax, 0x148(%rsp)
leaq 0x150(%rsp), %rdi
leaq 0x148(%rsp), %rsi
callq 0x11190
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x77(%rsp)
jne 0x61c5
jmp 0x61db
leaq 0x150(%rsp), %rdi
callq 0x11200
movb 0x4(%rax), %al
xorb $-0x1, %al
movb %al, 0x77(%rsp)
movb 0x77(%rsp), %al
testb $0x1, %al
jne 0x61e8
jmp 0x629d
movl 0x1c4(%rsp), %eax
incl %eax
movl %eax, 0x1c4(%rsp)
leaq 0x150(%rsp), %rdi
callq 0x11200
movl (%rax), %esi
movq 0x178(%rsp), %rax
movl (%rax), %edx
leaq 0x248(%rsp), %rdi
callq 0x10dc0
jmp 0x6220
jmp 0x629d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x65f9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x65ec
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
jmp 0x628b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f8(%rsp)
movl %eax, 0x2f4(%rsp)
leaq 0x1a0(%rsp), %rdi
callq 0x31f0
leaq 0x19f(%rsp), %rdi
callq 0x3300
jmp 0x65ec
jmp 0x629f
leaq 0x168(%rsp), %rdi
callq 0x10660
jmp 0x6115
leaq 0x1c8(%rsp), %rax
movq %rax, 0x140(%rsp)
movq 0x140(%rsp), %rdi
callq 0x102f0
movq %rax, 0x138(%rsp)
movq 0x140(%rsp), %rdi
callq 0x10320
movq %rax, 0x130(%rsp)
leaq 0x138(%rsp), %rdi
leaq 0x130(%rsp), %rsi
callq 0x10350
testb $0x1, %al
jne 0x6309
jmp 0x6409
leaq 0x138(%rsp), %rdi
callq 0x10390
movl (%rax), %eax
movl %eax, 0x12c(%rsp)
movq 0x178(%rsp), %rax
movl (%rax), %eax
movl 0x12c(%rsp), %ecx
xorl %ecx, %eax
movl %eax, 0x128(%rsp)
leaq 0x268(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x111d0
movq %rax, 0x68(%rsp)
jmp 0x6355
movq 0x68(%rsp), %rax
movq %rax, 0x120(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x11160
movq %rax, 0x118(%rsp)
leaq 0x120(%rsp), %rdi
leaq 0x118(%rsp), %rsi
callq 0x11190
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x67(%rsp)
jne 0x639b
jmp 0x63b1
leaq 0x120(%rsp), %rdi
callq 0x11200
movb 0x4(%rax), %al
xorb $-0x1, %al
movb %al, 0x67(%rsp)
movb 0x67(%rsp), %al
testb $0x1, %al
jne 0x63bb
jmp 0x63f5
movl 0x1c0(%rsp), %eax
incl %eax
movl %eax, 0x1c0(%rsp)
leaq 0x120(%rsp), %rdi
callq 0x11200
movl (%rax), %esi
movq 0x178(%rsp), %rax
movl (%rax), %edx
leaq 0x248(%rsp), %rdi
callq 0x10dc0
jmp 0x63f3
jmp 0x63f5
jmp 0x63f7
leaq 0x138(%rsp), %rdi
callq 0x10660
jmp 0x62eb
jmp 0x640b
leaq 0x188(%rsp), %rdi
callq 0x11220
jmp 0x609c
callq 0x10a60
movq %rax, 0x58(%rsp)
jmp 0x6429
movq 0x58(%rsp), %rdi
callq 0x10b90
jmp 0x6435
movl 0x2c8(%rsp), %eax
movl %eax, 0x4c(%rsp)
movl 0x264(%rsp), %eax
movl %eax, 0x50(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x10eb0
movl %eax, 0x54(%rsp)
jmp 0x645e
movl 0x4c(%rsp), %eax
movl 0x50(%rsp), %edx
movl 0x54(%rsp), %ecx
subl %edx, %ecx
addl %ecx, %eax
cltq
movq %rax, 0x38(%rsp)
movslq 0x2c8(%rsp), %rax
movq %rax, 0x30(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x11250
movq 0x30(%rsp), %rdx
movq %rax, %rcx
movq 0x38(%rsp), %rax
subq %rdx, %rcx
addq %rcx, %rax
movq %rax, 0x110(%rsp)
movq 0x3db27(%rip), %rdi     # 0x43fd8
leaq 0x29ed8(%rip), %rsi     # 0x30390
callq 0x32c0
movq %rax, 0x40(%rsp)
jmp 0x64c4
movq 0x40(%rsp), %rdi
movl 0x1c4(%rsp), %esi
callq 0x3440
movq %rax, 0x28(%rsp)
jmp 0x64dc
movq 0x28(%rsp), %rdi
movq 0x3dae0(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x64ef
movq 0x3dae2(%rip), %rdi     # 0x43fd8
leaq 0x29eb3(%rip), %rsi     # 0x303b0
callq 0x32c0
movq %rax, 0x20(%rsp)
jmp 0x6509
movq 0x20(%rsp), %rdi
movl 0x1c0(%rsp), %esi
callq 0x3440
movq %rax, 0x18(%rsp)
jmp 0x6521
movq 0x18(%rsp), %rdi
movq 0x3da9b(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x6534
movq 0x3da9d(%rip), %rdi     # 0x43fd8
leaq 0x29e8f(%rip), %rsi     # 0x303d1
callq 0x32c0
movq %rax, 0x10(%rsp)
jmp 0x654e
movq 0x10(%rsp), %rdi
movq 0x110(%rsp), %rsi
callq 0x30d0
movq %rax, 0x8(%rsp)
jmp 0x6567
movq 0x8(%rsp), %rdi
movq 0x3da55(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x657a
cmpq $0x17e6, 0x110(%rsp) # imm = 0x17E6
jne 0x658a
jmp 0x65a9
leaq 0x29e55(%rip), %rdi     # 0x303e6
leaq 0x29e6a(%rip), %rsi     # 0x30402
movl $0xec, %edx
leaq 0x29e70(%rip), %rcx     # 0x30414
callq 0x3200
leaq 0x1c8(%rsp), %rdi
callq 0x107c0
leaq 0x1e0(%rsp), %rdi
callq 0x107c0
leaq 0x248(%rsp), %rdi
callq 0x10ec0
leaq 0x268(%rsp), %rdi
callq 0x11260
leaq 0x2a0(%rsp), %rdi
callq 0x31f0
jmp 0x662f
leaq 0x1c8(%rsp), %rdi
callq 0x107c0
leaq 0x1e0(%rsp), %rdi
callq 0x107c0
leaq 0x248(%rsp), %rdi
callq 0x10ec0
leaq 0x268(%rsp), %rdi
callq 0x11260
leaq 0x2a0(%rsp), %rdi
callq 0x31f0
jmp 0x6644
leaq 0x300(%rsp), %rdi
callq 0x30c0
addq $0x518, %rsp            # imm = 0x518
retq
leaq 0x300(%rsp), %rdi
callq 0x30c0
movq 0x2f8(%rsp), %rdi
callq 0x3460
nop