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

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

                // array for storing values (max n numbers)
                int *vals = new int[n];

                const int MAX_NODES = (int)std::pow(2, bpn);
                DataStructures::UnionFind uf(MAX_NODES);    // total number of elements (2^24)
                std::vector<bool> mapa(MAX_NODES, false);   // total number of elements bits for quick lookup (whether the particular node exists or not)

                int k = 0, dups = 0; int j = 0;
                char ntxt[25];

                while (!file.eof())
                {
                    std::getline(file, node);
                    int i = 0, z = 0;
                    // remove whitespaces from the line
                    while (i < 47)
                    {
                        if (node.c_str()[i] == ' ' || node.c_str()[i] == '\n')
                        {
                            ++i;
                            continue;
                        }
                        else
                            ntxt[z] = node.c_str()[i];

                        i++; z++;
                    }
                    ntxt[24] = '\0';
                    std::bitset<24> bit_node(ntxt);
                    int nodeNumber = bit_node.to_ulong();
                    // if something's already in map, we skip it
                    if (mapa[nodeNumber])
                    {
                        dups++;
                        continue;
                    }
                    mapa[nodeNumber] = true;    // then we set its bit to true (it's added)
                    vals[k] = nodeNumber;
                    k++; j++;
                }
                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 (faster algo)");
                // iterate through all the elements (- duplicates!) and find their immediate neighbors (distance < 3)
                for (int i = 0; i < n - dups; i++)
                {
                    for (auto d : distances_one)
                    {
                        int resNode = vals[i] ^ d;
                        bool exists = mapa[resNode];         // is computed node in a graph?
                        if (exists)                          // if yes, connect it to our current node (vals[i])
                        {
                            // add to UF (there is an edge from current element to the one 1 Hamming distance away)
                            num_edg_cost_one++;
                            uf.Union(vals[i], resNode);
                        }
                    }
                    for (auto d : distances_two)
                    {
                        int resNode = vals[i] ^ d;             // same thing here, only distance = 2
                        bool exists = mapa[resNode];
                        if (exists)
                        {
                            // add node connected to current one 2 Hamming distances away
                            num_edg_cost_two++;
                            uf.Union(vals[i], resNode);
                        }
                    }
                }
                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 (+1 for the one whose duplicates we found)
                // to get number of clusters that are at least 3 Hamming distances away from others
                int totalNumberClusters = n - (MAX_NODES - uf.count()) - dups + 1;
                std::cout << "Edges 1 Hamming distance away: " << num_edg_cost_one/2 << std::endl;
                std::cout << "Edges 2 Hamming distances away: " << num_edg_cost_two/2 << std::endl;
                std::cout << "Number of clusters: " << totalNumberClusters << std::endl;
                assert(totalNumberClusters == 6118);

                delete[] vals;
            }
        }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x318, %rsp            # imm = 0x318
movq %rdi, %rsi
leaq 0x108(%rsp), %rdi
pushq $0x8
popq %rdx
callq 0x2360
leaq 0x188(%rsp), %rdi
callq 0x20c0
testb %al, %al
je 0x4196
callq 0x725c
movq %rax, %rbx
leaq 0x970b(%rip), %rsi      # 0xd4ac
leaq 0x30(%rsp), %rdi
leaq 0x90(%rsp), %rdx
callq 0x2120
leaq 0x30(%rsp), %rsi
movq %rbx, %rdi
callq 0x72a6
leaq 0x30(%rsp), %rdi
callq 0x2150
leaq 0x108(%rsp), %rdi
leaq 0x4(%rsp), %rsi
callq 0x21a0
movq %rsp, %rsi
movq %rax, %rdi
callq 0x21a0
leaq 0xa0(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x108(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x2080
movslq 0x4(%rsp), %rax
leaq (,%rax,4), %rcx
testq %rax, %rax
pushq $-0x1
popq %rdi
cmovnsq %rcx, %rdi
callq 0x2030
movq %rax, 0x18(%rsp)
movl (%rsp), %edi
movsd 0x9294(%rip), %xmm0     # 0xd0d0
callq 0x22f0
cvttsd2si %xmm0, %ebx
leaq 0x58(%rsp), %rdi
movl %ebx, %esi
callq 0x73a0
movl %ebx, 0x24(%rsp)
movslq %ebx, %rsi
leaq 0x70(%rsp), %rdx
movb $0x0, (%rdx)
leaq 0x30(%rsp), %rdi
leaq 0xe0(%rsp), %rcx
callq 0x74ee
movq $0x0, 0x10(%rsp)
pushq $0x30
popq %r14
pushq $0x31
popq %r15
leaq 0x30(%rsp), %r12
xorl %r13d, %r13d
movq 0x108(%rsp), %rax
movq -0x18(%rax), %rax
testb $0x2, 0x128(%rsp,%rax)
jne 0x3f60
leaq 0x108(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x2080
movq 0x90(%rsp), %rax
xorl %ecx, %ecx
xorl %edx, %edx
movslq %edx, %rdx
cmpq $0x2e, %rdx
jg 0x3ef2
movzbl (%rax,%rdx), %esi
cmpl $0x20, %esi
je 0x3edd
cmpl $0xa, %esi
jne 0x3ee2
incq %rdx
jmp 0x3ec9
movb %sil, 0xe0(%rsp,%rcx)
incq %rdx
incq %rcx
jmp 0x3ec6
movb $0x0, 0xf8(%rsp)
leaq 0x70(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
pushq $-0x1
popq %rdx
movl %r14d, %ecx
movl %r15d, %r8d
callq 0x7552
movq 0x70(%rsp), %rbp
movslq %ebp, %rbx
movq %r12, %rdi
movq %rbx, %rsi
callq 0x75b0
testq %rdx, (%rax)
je 0x3f3e
movq 0x10(%rsp), %rax
incl %eax
movq %rax, 0x10(%rsp)
jmp 0x3e8b
movq %r12, %rdi
movq %rbx, %rsi
callq 0x75b0
orq %rdx, (%rax)
movslq %r13d, %r13
movq 0x18(%rsp), %rax
movl %ebp, (%rax,%r13,4)
incl %r13d
jmp 0x3e8b
leaq 0x108(%rsp), %rdi
callq 0x2040
callq 0x725c
movq %rax, %rdi
callq 0x72c8
movl (%rsp), %esi
leaq 0xc8(%rsp), %rdi
pushq $0x1
popq %rdx
callq 0x3701
movl (%rsp), %esi
leaq 0xb0(%rsp), %rdi
pushq $0x2
popq %rdx
callq 0x3701
callq 0x725c
movq %rax, %rbx
leaq 0x9525(%rip), %rsi      # 0xd4d4
leaq 0x70(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x2120
leaq 0x70(%rsp), %rsi
movq %rbx, %rdi
callq 0x72a6
leaq 0x70(%rsp), %rdi
callq 0x2150
xorl %r14d, %r14d
movslq 0x10(%rsp), %rax
movq %rax, 0x28(%rsp)
movl $0x0, 0xc(%rsp)
xorl %r12d, %r12d
movslq 0x4(%rsp), %rax
subq 0x28(%rsp), %rax
cmpq %rax, %r14
jge 0x40a1
movq 0xc8(%rsp), %r15
movq 0xd0(%rsp), %r13
cmpq %r13, %r15
je 0x404c
movq 0x18(%rsp), %rax
movl (%rax,%r14,4), %ebp
movl (%r15), %ebx
xorl %ebp, %ebx
movslq %ebx, %rsi
leaq 0x30(%rsp), %rdi
callq 0x75b0
testq %rdx, (%rax)
je 0x4046
incl %r12d
leaq 0x58(%rsp), %rdi
movl %ebp, %esi
movl %ebx, %edx
callq 0x741e
addq $0x4, %r15
jmp 0x4010
movq 0xb0(%rsp), %r15
movq 0xb8(%rsp), %r13
cmpq %r13, %r15
je 0x4099
movq 0x18(%rsp), %rax
movl (%rax,%r14,4), %ebx
movl (%r15), %ebp
xorl %ebx, %ebp
movslq %ebp, %rsi
leaq 0x30(%rsp), %rdi
callq 0x75b0
testq %rdx, (%rax)
je 0x4093
incl 0xc(%rsp)
leaq 0x58(%rsp), %rdi
movl %ebx, %esi
movl %ebp, %edx
callq 0x741e
addq $0x4, %r15
jmp 0x405c
incq %r14
jmp 0x3fed
callq 0x725c
movq %rax, %rdi
callq 0x72c8
movl 0x4(%rsp), %ebx
movl 0x68(%rsp), %r14d
movq 0x11f1a(%rip), %rdi     # 0x15fd8
leaq 0x931e(%rip), %rsi      # 0xd3e3
callq 0x2230
movq %rax, %rdi
movl %r12d, %eax
cltd
pushq $0x2
popq %rcx
idivl %ecx
movl %eax, %esi
callq 0x2370
movq %rax, %rdi
callq 0x2160
movq 0x11eec(%rip), %rdi     # 0x15fd8
leaq 0x9310(%rip), %rsi      # 0xd403
callq 0x2230
movq %rax, %rdi
movl 0xc(%rsp), %eax
cltd
pushq $0x2
popq %rcx
idivl %ecx
movl %eax, %esi
callq 0x2370
movq %rax, %rdi
callq 0x2160
movq 0x11ebd(%rip), %rdi     # 0x15fd8
leaq 0x9302(%rip), %rsi      # 0xd424
callq 0x2230
movq 0x10(%rsp), %rcx
addl 0x24(%rsp), %ecx
subl %ecx, %ebx
addl %r14d, %ebx
incl %ebx
movq %rax, %rdi
movl %ebx, %esi
callq 0x2370
movq %rax, %rdi
callq 0x2160
cmpl $0x17e6, %ebx           # imm = 0x17E6
jne 0x41b5
movq 0x18(%rsp), %rdi
callq 0x2270
leaq 0xb0(%rsp), %rdi
callq 0x9cda
leaq 0xc8(%rsp), %rdi
callq 0x9cda
leaq 0x30(%rsp), %rdi
callq 0x75ea
leaq 0x58(%rsp), %rdi
callq 0x746c
leaq 0x90(%rsp), %rdi
callq 0x2150
leaq 0x108(%rsp), %rdi
callq 0x20b0
addq $0x318, %rsp            # imm = 0x318
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x927d(%rip), %rdi      # 0xd439
leaq 0x9292(%rip), %rsi      # 0xd455
leaq 0x9327(%rip), %rcx      # 0xd4f1
movl $0x152, %edx            # imm = 0x152
callq 0x21b0
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x2150
jmp 0x4223
jmp 0x4220
movq %rax, %rbx
jmp 0x4230
jmp 0x4219
movq %rax, %rbx
jmp 0x4247
jmp 0x41f5
jmp 0x41f5
movq %rax, %rbx
jmp 0x4251
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
jmp 0x4259
jmp 0x4208
jmp 0x4208
movq %rax, %rbx
jmp 0x425e
jmp 0x4220
jmp 0x4219
jmp 0x4220
jmp 0x4219
jmp 0x4219
jmp 0x4219
movq %rax, %rbx
jmp 0x423d
jmp 0x4220
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
callq 0x9cda
leaq 0xc8(%rsp), %rdi
callq 0x9cda
leaq 0x30(%rsp), %rdi
callq 0x75ea
leaq 0x58(%rsp), %rdi
callq 0x746c
leaq 0x90(%rsp), %rdi
callq 0x2150
leaq 0x108(%rsp), %rdi
callq 0x20b0
movq %rbx, %rdi
callq 0x2380