// File: /workspace/github_cpp_makefile_star2_O1/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
movl $0x8, %edx
callq 0x2340
leaq 0x188(%rsp), %rdi
callq 0x20b0
testb %al, %al
je 0x4a44
callq 0x88b8
movq %rax, %rbx
leaq 0x30(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0xa0b2(%rip), %rsi      # 0xe4fc
leaq 0xa0d2(%rip), %rdx      # 0xe523
leaq 0x20(%rsp), %rdi
callq 0xbb3a
leaq 0x20(%rsp), %rsi
movq %rbx, %rdi
callq 0x8904
movq 0x20(%rsp), %rdi
cmpq %r14, %rdi
je 0x4477
callq 0x2200
leaq 0x108(%rsp), %rbx
leaq 0x10(%rsp), %rsi
movq %rbx, %rdi
callq 0x2160
leaq 0x14(%rsp), %rsi
movq %rax, %rdi
callq 0x2160
leaq 0xa0(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movq 0x108(%rsp), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x2210
movsbl %al, %edx
leaq 0x108(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x2380
movslq 0x10(%rsp), %rax
leaq (,%rax,4), %rcx
testq %rax, %rax
movq $-0x1, %rdi
cmovnsq %rcx, %rdi
callq 0x2030
movq %rax, 0x18(%rsp)
movl 0x14(%rsp), %edi
movsd 0x9c0e(%rip), %xmm0     # 0xe120
callq 0x22d0
cvttsd2si %xmm0, %ebx
leaq 0x78(%rsp), %rdi
movl %ebx, %esi
callq 0x8a78
movl %ebx, 0x4c(%rsp)
movslq %ebx, %rsi
leaq 0x50(%rsp), %rdx
movb $0x0, (%rdx)
leaq 0x20(%rsp), %rdi
leaq 0xe0(%rsp), %rcx
callq 0x8c26
movq 0x108(%rsp), %rax
movq -0x18(%rax), %rax
xorl %ebx, %ebx
testb $0x2, 0x128(%rsp,%rax)
jne 0x46c3
leaq (%rsp,%rax), %rdi
addq $0x108, %rdi            # imm = 0x108
xorl %r14d, %r14d
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
leaq 0xe0(%rsp), %r12
leaq 0x50(%rsp), %r13
movq %rax, %rbp
leaq 0x3f(%rax), %r15
xorl %ebx, %ebx
movl $0xa, %esi
callq 0x2210
movsbl %al, %edx
leaq 0x108(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x2380
xorl %eax, %eax
movq 0x90(%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 0x45e4
cmpl $0xa, %r8d
jne 0x45f8
incq %rdx
leal (%rdi,%rsi), %r8d
incl %r8d
incl %esi
cmpl $0x2, %r8d
jne 0x45d3
jmp 0x4609
movb %r8b, 0xe0(%rsp,%rax)
incq %rax
cmpq $0x2e, %rdx
jl 0x45c0
movb $0x0, 0xf8(%rsp)
movq $0x0, 0x50(%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 0xbcfc
movq 0x50(%rsp), %rcx
movslq %ecx, %rsi
leaq 0x3f(%rsi), %rax
testq %rsi, %rsi
cmovnsq %rsi, %rax
sarq $0x6, %rax
shlq $0x3, %rax
addq 0x20(%rsp), %rax
andq %r15, %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 0x4684
incl %ebx
jmp 0x46a2
leaq -0x8(,%rdx,8), %rdx
orq %rsi, %rdi
movq %rdi, (%rax,%rdx)
movslq %r14d, %r14
movq 0x18(%rsp), %rax
movl %ecx, (%rax,%r14,4)
incl %r14d
movq 0x108(%rsp), %rax
movq -0x18(%rax), %rax
leaq (%rsp,%rax), %rdi
addq $0x108, %rdi            # imm = 0x108
testb $0x2, 0x20(%rdi)
je 0x4592
leaq 0x108(%rsp), %rdi
callq 0x2050
callq 0x88b8
movq %rax, %rdi
callq 0x894e
movl 0x14(%rsp), %esi
leaq 0xc8(%rsp), %rdi
movl $0x1, %edx
callq 0x3ba8
movl 0x14(%rsp), %esi
leaq 0xb0(%rsp), %rdi
movl $0x2, %edx
callq 0x3ba8
callq 0x88b8
movq %rax, %r14
leaq 0x60(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x9e03(%rip), %rsi      # 0xe524
leaq 0x9e18(%rip), %rdx      # 0xe540
leaq 0x50(%rsp), %rdi
callq 0xbb3a
leaq 0x50(%rsp), %rsi
movq %r14, %rdi
callq 0x8904
movq 0x50(%rsp), %rdi
cmpq %r15, %rdi
je 0x474e
callq 0x2200
xorl %r14d, %r14d
movl $0x0, %r15d
cmpl %ebx, 0x10(%rsp)
jle 0x48a2
xorl %r15d, %r15d
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
movl %ebx, 0x48(%rsp)
movslq %ebx, %rcx
movq %rcx, 0x70(%rsp)
leaq 0x3f(%rax), %rbx
xorl %ebp, %ebp
xorl %r12d, %r12d
movq 0xc8(%rsp), %r14
movq 0xd0(%rsp), %r13
cmpq %r13, %r14
je 0x47f8
movq 0x18(%rsp), %rax
movl (%rax,%r15,4), %esi
movl (%r14), %edx
xorl %esi, %edx
movslq %edx, %rax
leaq 0x3f(%rax), %rcx
testq %rax, %rax
cmovnsq %rax, %rcx
sarq $0x6, %rcx
shlq $0x3, %rcx
addq 0x20(%rsp), %rcx
movq %rax, %rdi
andq %rbx, %rdi
xorl %r8d, %r8d
movabsq $-0x8000000000000000, %r9 # imm = 0x8000000000000000
cmpq %r9, %rdi
setbe %r8b
movq -0x8(%rcx,%r8,8), %rcx
btq %rax, %rcx
jae 0x47f2
incl %ebp
leaq 0x78(%rsp), %rdi
callq 0x8b72
addq $0x4, %r14
jmp 0x4793
movq 0xb0(%rsp), %r14
movq 0xb8(%rsp), %r13
cmpq %r13, %r14
je 0x486e
movq 0x18(%rsp), %rax
movl (%rax,%r15,4), %esi
movl (%r14), %edx
xorl %esi, %edx
movslq %edx, %rax
leaq 0x3f(%rax), %rcx
testq %rax, %rax
cmovnsq %rax, %rcx
sarq $0x6, %rcx
shlq $0x3, %rcx
addq 0x20(%rsp), %rcx
movq %rax, %rdi
andq %rbx, %rdi
xorl %r8d, %r8d
movabsq $-0x8000000000000000, %r9 # imm = 0x8000000000000000
cmpq %r9, %rdi
setbe %r8b
movq -0x8(%rcx,%r8,8), %rcx
btq %rax, %rcx
jae 0x4868
incl %r12d
leaq 0x78(%rsp), %rdi
callq 0x8b72
addq $0x4, %r14
jmp 0x4808
incq %r15
movslq 0x10(%rsp), %rax
subq 0x70(%rsp), %rax
cmpq %rax, %r15
jl 0x4783
movl %ebp, %r15d
shrl $0x1f, %r15d
addl %ebp, %r15d
sarl %r15d
movl %r12d, %r14d
shrl $0x1f, %r14d
addl %r12d, %r14d
sarl %r14d
movl 0x48(%rsp), %ebx
callq 0x88b8
movq %rax, %rdi
callq 0x894e
movl %ebx, %r13d
movl 0x10(%rsp), %ebx
movl 0x88(%rsp), %r12d
movq 0x10713(%rip), %rdi     # 0x14fd8
leaq 0x9b67(%rip), %rsi      # 0xe433
movl $0x1f, %edx
callq 0x2250
movq 0x106fb(%rip), %rdi     # 0x14fd8
movl %r15d, %esi
callq 0x2350
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x2210
movsbl %al, %esi
movq %r15, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
movq 0x106c2(%rip), %rdi     # 0x14fd8
leaq 0x9b36(%rip), %rsi      # 0xe453
movl $0x20, %edx
callq 0x2250
movq 0x106aa(%rip), %rdi     # 0x14fd8
movl %r14d, %esi
callq 0x2350
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2210
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
movq 0x10671(%rip), %rdi     # 0x14fd8
leaq 0x9b06(%rip), %rsi      # 0xe474
movl $0x14, %edx
callq 0x2250
addl 0x4c(%rsp), %r13d
subl %r13d, %ebx
leal (%r12,%rbx), %ebp
incl %ebp
movq 0x1064b(%rip), %rdi     # 0x14fd8
movl %ebp, %esi
callq 0x2350
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2210
movsbl %al, %esi
movq %r14, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2190
cmpl $0x17e6, %ebp           # imm = 0x17E6
jne 0x4a63
movq 0x18(%rsp), %rdi
callq 0x2270
movq 0xb0(%rsp), %rdi
testq %rdi, %rdi
je 0x49e6
callq 0x2200
movq 0xc8(%rsp), %rdi
testq %rdi, %rdi
je 0x49f8
callq 0x2200
movq 0x20(%rsp), %rdi
testq %rdi, %rdi
je 0x4a20
callq 0x2200
xorl %eax, %eax
movq %rax, 0x20(%rsp)
movl %eax, 0x28(%rsp)
movq %rax, 0x30(%rsp)
movl %eax, 0x38(%rsp)
movq %rax, 0x40(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x8bba
movq 0x90(%rsp), %rdi
leaq 0xa0(%rsp), %rax
cmpq %rax, %rdi
je 0x4a44
callq 0x2200
leaq 0x108(%rsp), %rdi
callq 0x20a0
addq $0x318, %rsp            # imm = 0x318
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x9a1f(%rip), %rdi      # 0xe489
leaq 0x9a34(%rip), %rsi      # 0xe4a5
leaq 0x9ac9(%rip), %rcx      # 0xe541
movl $0x152, %edx            # imm = 0x152
callq 0x2170
movq %rax, %rbx
movq 0x50(%rsp), %rdi
cmpq %r15, %rdi
je 0x4ad6
callq 0x2200
jmp 0x4ad6
jmp 0x4ad3
movq %rax, %rbx
jmp 0x4ae8
jmp 0x4afe
movq %rax, %rbx
jmp 0x4b29
jmp 0x4ac5
jmp 0x4ac5
movq %rax, %rbx
movq 0x20(%rsp), %rdi
cmpq %r14, %rdi
jne 0x4b48
jmp 0x4b4d
jmp 0x4aca
jmp 0x4aca
movq %rax, %rbx
jmp 0x4b33
movq %rax, %rbx
jmp 0x4b4d
jmp 0x4ad3
jmp 0x4afe
movq %rax, %rbx
movq 0xb0(%rsp), %rdi
testq %rdi, %rdi
je 0x4ae8
callq 0x2200
movq 0xc8(%rsp), %rdi
testq %rdi, %rdi
je 0x4b01
callq 0x2200
jmp 0x4b01
jmp 0x4afe
movq %rax, %rbx
movq 0x20(%rsp), %rdi
testq %rdi, %rdi
je 0x4b29
callq 0x2200
xorl %eax, %eax
movq %rax, 0x20(%rsp)
movl %eax, 0x28(%rsp)
movq %rax, 0x30(%rsp)
movl %eax, 0x38(%rsp)
movq %rax, 0x40(%rsp)
leaq 0x78(%rsp), %rdi
callq 0x8bba
movq 0x90(%rsp), %rdi
leaq 0xa0(%rsp), %rax
cmpq %rax, %rdi
je 0x4b4d
callq 0x2200
leaq 0x108(%rsp), %rdi
callq 0x20a0
movq %rbx, %rdi
callq 0x2360