// File: /workspace/github_cpp_makefile_star2_O3/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 $0x328, %rsp            # imm = 0x328
movq %rdi, %rsi
leaq 0x118(%rsp), %rdi
movl $0x8, %edx
callq 0x2330
leaq 0x198(%rsp), %rdi
callq 0x20b0
testb %al, %al
je 0x49c9
callq 0x88f8
movq %rax, %rbx
leaq 0x48(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0xa140(%rip), %rsi      # 0xe4fc
leaq 0xa160(%rip), %rdx      # 0xe523
leaq 0x38(%rsp), %rdi
callq 0xbb78
leaq 0x38(%rsp), %rsi
movq %rbx, %rdi
callq 0x8942
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
je 0x43e9
callq 0x21f0
leaq 0x118(%rsp), %rbx
leaq 0x18(%rsp), %rsi
movq %rbx, %rdi
callq 0x2160
leaq 0x1c(%rsp), %rsi
movq %rax, %rdi
callq 0x2160
leaq 0xb0(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movq 0x118(%rsp), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x2200
movsbl %al, %edx
leaq 0x118(%rsp), %rdi
leaq 0xa0(%rsp), %rsi
callq 0x2370
movslq 0x18(%rsp), %rax
leaq (,%rax,4), %rcx
testq %rax, %rax
movq $-0x1, %rdi
cmovnsq %rcx, %rdi
callq 0x2030
movq %rax, 0x20(%rsp)
movl 0x1c(%rsp), %edi
movsd 0x9c9c(%rip), %xmm0     # 0xe120
callq 0x22c0
cvttsd2si %xmm0, %ebx
leaq 0x88(%rsp), %rdi
movl %ebx, %esi
callq 0x8ab6
movl %ebx, 0x2c(%rsp)
movslq %ebx, %rsi
leaq 0x60(%rsp), %rdx
movb $0x0, (%rdx)
leaq 0x38(%rsp), %rdi
leaq 0xf0(%rsp), %rcx
callq 0x8c64
movq 0x118(%rsp), %rax
movq -0x18(%rax), %rax
movl $0x0, 0x14(%rsp)
testb $0x2, 0x138(%rsp,%rax)
jne 0x4641
leaq (%rsp,%rax), %rdi
addq $0x118, %rdi            # imm = 0x118
xorl %ebx, %ebx
movabsq $-0x8000000000000000, %rbp # imm = 0x8000000000000000
leaq 0xa0(%rsp), %r15
leaq 0xf0(%rsp), %r12
leaq 0x60(%rsp), %r13
leaq 0x3f(%rbp), %r14
movl $0x0, 0x14(%rsp)
movl $0xa, %esi
callq 0x2200
movsbl %al, %edx
leaq 0x118(%rsp), %rdi
movq %r15, %rsi
callq 0x2370
xorl %eax, %eax
movq 0xa0(%rsp), %rcx
xorl %esi, %esi
movslq %esi, %rdx
cmpl $0x2f, %edx
movl $0x2e, %edi
cmovgel %edx, %edi
leal 0x1(%rdx), %esi
negl %edi
movzbl (%rcx,%rdx), %r8d
cmpl $0x20, %r8d
je 0x4564
cmpl $0xa, %r8d
jne 0x4578
incq %rdx
leal (%rdi,%rsi), %r8d
incl %r8d
incl %esi
cmpl $0x2, %r8d
jne 0x4553
jmp 0x4589
movb %r8b, 0xf0(%rsp,%rax)
incq %rax
cmpq $0x2e, %rdx
jl 0x4540
movb $0x0, 0x108(%rsp)
movq $0x0, 0x60(%rsp)
movq %r12, %rdi
callq 0x2120
movl $0x31, (%rsp)
movq %r13, %rdi
movq %r12, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
movq %rax, %r8
movl $0x30, %r9d
callq 0xbd40
movq 0x60(%rsp), %rcx
movslq %ecx, %rsi
leal 0x3f(%rsi), %eax
testl %esi, %esi
cmovnsl %ecx, %eax
sarl $0x6, %eax
cltq
shlq $0x3, %rax
addq 0x38(%rsp), %rax
andq %r14, %rsi
xorl %edx, %edx
cmpq %rbp, %rsi
setbe %dl
movl $0x1, %esi
shlq %cl, %rsi
movq -0x8(%rax,%rdx,8), %rdi
btq %rcx, %rdi
jae 0x4604
incl 0x14(%rsp)
jmp 0x4620
leaq -0x8(,%rdx,8), %rdx
orq %rsi, %rdi
movq %rdi, (%rax,%rdx)
movslq %ebx, %rbx
movq 0x20(%rsp), %rax
movl %ecx, (%rax,%rbx,4)
incl %ebx
movq 0x118(%rsp), %rax
movq -0x18(%rax), %rax
leaq (%rsp,%rax), %rdi
addq $0x118, %rdi            # imm = 0x118
testb $0x2, 0x20(%rdi)
je 0x4517
leaq 0x118(%rsp), %rdi
callq 0x2050
callq 0x88f8
movq %rax, %rdi
callq 0x898c
movl 0x1c(%rsp), %esi
leaq 0xd8(%rsp), %rdi
movl $0x1, %edx
callq 0x3b87
movl 0x14(%rsp), %ebp
movl 0x1c(%rsp), %esi
leaq 0xc0(%rsp), %rdi
movl $0x2, %edx
callq 0x3b87
callq 0x88f8
movq %rax, %r14
leaq 0x70(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x9e81(%rip), %rsi      # 0xe524
leaq 0x9e96(%rip), %rdx      # 0xe540
leaq 0x60(%rsp), %rdi
callq 0xbb78
leaq 0x60(%rsp), %rsi
movq %r14, %rdi
callq 0x8942
movq 0x60(%rsp), %rdi
cmpq %r15, %rdi
je 0x46d0
callq 0x21f0
xorl %r14d, %r14d
movl $0x0, %r15d
cmpl %ebp, 0x18(%rsp)
jle 0x4842
xorl %ecx, %ecx
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
movslq %ebp, %rdx
movq %rdx, 0x80(%rsp)
leaq 0x3f(%rax), %r12
xorl %ebp, %ebp
xorl %ebx, %ebx
movq 0xd8(%rsp), %r14
movq 0xe0(%rsp), %r13
cmpq %r13, %r14
movq %rcx, 0x30(%rsp)
je 0x4784
movq 0x20(%rsp), %rax
movl (%rax,%rcx,4), %r15d
movl (%r14), %edx
xorl %r15d, %edx
movslq %edx, %rax
leal 0x3f(%rax), %ecx
testl %eax, %eax
cmovnsl %edx, %ecx
sarl $0x6, %ecx
movslq %ecx, %rcx
shlq $0x3, %rcx
addq 0x38(%rsp), %rcx
movq %rax, %rsi
andq %r12, %rsi
xorl %edi, %edi
movabsq $-0x8000000000000000, %r8 # imm = 0x8000000000000000
cmpq %r8, %rsi
setbe %dil
movq -0x8(%rcx,%rdi,8), %rcx
btq %rax, %rcx
jae 0x477b
incl %ebp
leaq 0x88(%rsp), %rdi
movl %r15d, %esi
callq 0x8bb0
addq $0x4, %r14
cmpq %r13, %r14
jne 0x4725
movq 0xc0(%rsp), %r14
movq 0xc8(%rsp), %r13
cmpq %r13, %r14
je 0x4806
movq 0x20(%rsp), %rax
movq 0x30(%rsp), %rcx
movl (%rax,%rcx,4), %r15d
movl (%r14), %edx
xorl %r15d, %edx
movslq %edx, %rax
leal 0x3f(%rax), %ecx
testl %eax, %eax
cmovnsl %edx, %ecx
sarl $0x6, %ecx
movslq %ecx, %rcx
shlq $0x3, %rcx
addq 0x38(%rsp), %rcx
movq %rax, %rsi
andq %r12, %rsi
xorl %edi, %edi
movabsq $-0x8000000000000000, %r8 # imm = 0x8000000000000000
cmpq %r8, %rsi
setbe %dil
movq -0x8(%rcx,%rdi,8), %rcx
btq %rax, %rcx
jae 0x47fd
incl %ebx
leaq 0x88(%rsp), %rdi
movl %r15d, %esi
callq 0x8bb0
addq $0x4, %r14
cmpq %r13, %r14
jne 0x47a7
movq 0x30(%rsp), %rcx
incq %rcx
movslq 0x18(%rsp), %rax
subq 0x80(%rsp), %rax
cmpq %rax, %rcx
jl 0x4702
movl %ebp, %r15d
shrl $0x1f, %r15d
addl %ebp, %r15d
sarl %r15d
movl %ebx, %r14d
shrl $0x1f, %r14d
addl %ebx, %r14d
sarl %r14d
movl 0x14(%rsp), %ebp
callq 0x88f8
movq %rax, %rdi
callq 0x898c
movl 0x18(%rsp), %ebx
movl 0x98(%rsp), %r12d
movq 0x10776(%rip), %rdi     # 0x14fd8
leaq 0x9bca(%rip), %rsi      # 0xe433
movl $0x1f, %edx
callq 0x2240
movq 0x1075e(%rip), %rdi     # 0x14fd8
movl %r15d, %esi
callq 0x2340
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2200
movsbl %al, %esi
movq %r15, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
movq 0x10725(%rip), %rdi     # 0x14fd8
leaq 0x9b99(%rip), %rsi      # 0xe453
movl $0x20, %edx
callq 0x2240
movq 0x1070d(%rip), %rdi     # 0x14fd8
movl %r14d, %esi
callq 0x2340
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2200
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
movq 0x106d4(%rip), %rdi     # 0x14fd8
leaq 0x9b69(%rip), %rsi      # 0xe474
movl $0x14, %edx
callq 0x2240
addl 0x2c(%rsp), %ebp
subl %ebp, %ebx
leal (%r12,%rbx), %ebp
incl %ebp
movq 0x106b0(%rip), %rdi     # 0x14fd8
movl %ebp, %esi
callq 0x2340
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2200
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
cmpl $0x17e6, %ebp           # imm = 0x17E6
jne 0x49e8
movq 0x20(%rsp), %rdi
callq 0x2260
movq 0xc0(%rsp), %rdi
testq %rdi, %rdi
je 0x4981
callq 0x21f0
movq 0xd8(%rsp), %rdi
testq %rdi, %rdi
je 0x4993
callq 0x21f0
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
je 0x49a2
callq 0x21f0
leaq 0x88(%rsp), %rdi
callq 0x8bf8
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x49c9
callq 0x21f0
leaq 0x118(%rsp), %rdi
callq 0x20a0
addq $0x328, %rsp            # imm = 0x328
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x9a9a(%rip), %rdi      # 0xe489
leaq 0x9aaf(%rip), %rsi      # 0xe4a5
leaq 0x9b44(%rip), %rcx      # 0xe541
movl $0x152, %edx            # imm = 0x152
callq 0x2170
movq %rax, %rbx
movq 0x60(%rsp), %rdi
cmpq %r15, %rdi
je 0x4a58
callq 0x21f0
jmp 0x4a58
jmp 0x4a55
movq %rax, %rbx
jmp 0x4a6a
jmp 0x4a80
movq %rax, %rbx
jmp 0x4aa6
jmp 0x4a47
jmp 0x4a47
movq %rax, %rbx
movq 0x38(%rsp), %rdi
cmpq %r14, %rdi
jne 0x4ac8
jmp 0x4acd
jmp 0x4a4c
jmp 0x4a4c
movq %rax, %rbx
jmp 0x4ab3
movq %rax, %rbx
jmp 0x4acd
jmp 0x4a55
jmp 0x4a80
movq %rax, %rbx
movq 0xc0(%rsp), %rdi
testq %rdi, %rdi
je 0x4a6a
callq 0x21f0
movq 0xd8(%rsp), %rdi
testq %rdi, %rdi
je 0x4a83
callq 0x21f0
jmp 0x4a83
jmp 0x4a80
movq %rax, %rbx
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
je 0x4aa6
callq 0x21f0
xorl %eax, %eax
movq %rax, 0x38(%rsp)
movl $0x0, 0x40(%rsp)
movq %rax, 0x48(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x8bf8
movq 0xa0(%rsp), %rdi
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x4acd
callq 0x21f0
leaq 0x118(%rsp), %rdi
callq 0x20a0
movq %rbx, %rdi
callq 0x2350