// File: 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:
subq $0x508, %rsp            # imm = 0x508
movq %rdi, 0x500(%rsp)
movq 0x500(%rsp), %rsi
leaq 0x2f0(%rsp), %rdi
movq %rdi, 0xf8(%rsp)
movl $0x8, %edx
callq 0x3410
movq 0xf8(%rsp), %rdi
callq 0x3430
movb %al, 0x103(%rsp)
jmp 0x66f7
movb 0x103(%rsp), %al
testb $0x1, %al
jne 0x6707
jmp 0x7234
callq 0x10a60
movq %rax, 0xf0(%rsp)
jmp 0x6716
leaq 0x2bf(%rsp), %rdi
movq %rdi, 0xe8(%rsp)
callq 0x3470
movq 0xe8(%rsp), %rdx
leaq 0x29d1f(%rip), %rsi     # 0x30459
leaq 0x2c0(%rsp), %rdi
callq 0x3360
jmp 0x6749
movq 0xf0(%rsp), %rdi
leaq 0x2c0(%rsp), %rsi
callq 0x10ad0
jmp 0x6760
leaq 0x2c0(%rsp), %rdi
callq 0x31f0
leaq 0x2bf(%rsp), %rdi
callq 0x3300
leaq 0x2f0(%rsp), %rdi
leaq 0x2b8(%rsp), %rsi
callq 0x31e0
movq %rax, 0xe0(%rsp)
jmp 0x6799
movq 0xe0(%rsp), %rdi
leaq 0x2b4(%rsp), %rsi
callq 0x31e0
jmp 0x67b0
leaq 0x290(%rsp), %rdi
movq %rdi, 0xd8(%rsp)
callq 0x3370
movq 0xd8(%rsp), %rsi
leaq 0x2f0(%rsp), %rdi
callq 0x3080
jmp 0x67dc
movslq 0x2b8(%rsp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x3030
movq %rax, 0xd0(%rsp)
jmp 0x6809
movq 0xd0(%rsp), %rax
movq %rax, 0x288(%rsp)
movl 0x2b4(%rsp), %esi
movl $0x2, %edi
callq 0x10ff0
movsd %xmm0, 0xc8(%rsp)
jmp 0x6835
movsd 0xc8(%rsp), %xmm0
cvttsd2si %xmm0, %eax
movl %eax, 0x284(%rsp)
movl 0x284(%rsp), %esi
leaq 0x268(%rsp), %rdi
callq 0x10ca0
jmp 0x685f
movslq 0x284(%rsp), %rax
movq %rax, 0xb8(%rsp)
movb $0x0, 0x23f(%rsp)
leaq 0x23e(%rsp), %rdi
movq %rdi, 0xc0(%rsp)
callq 0x11270
movq 0xb8(%rsp), %rsi
movq 0xc0(%rsp), %rcx
leaq 0x240(%rsp), %rdi
leaq 0x23f(%rsp), %rdx
callq 0x11280
jmp 0x68b3
leaq 0x23e(%rsp), %rdi
callq 0x11300
movl $0x0, 0x238(%rsp)
movl $0x0, 0x234(%rsp)
movl $0x0, 0x230(%rsp)
movq 0x2f0(%rsp), %rax
movq -0x18(%rax), %rax
leaq 0x2f0(%rsp,%rax), %rdi
callq 0x3490
movb %al, 0xb7(%rsp)
jmp 0x6903
movb 0xb7(%rsp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x6915
jmp 0x6c0c
leaq 0x2f0(%rsp), %rdi
leaq 0x290(%rsp), %rsi
callq 0x3080
jmp 0x692c
movl $0x0, 0x20c(%rsp)
movl $0x0, 0x208(%rsp)
cmpl $0x2f, 0x20c(%rsp)
jge 0x6aab
leaq 0x290(%rsp), %rdi
callq 0x3140
movslq 0x20c(%rsp), %rcx
movsbl (%rax,%rcx), %eax
cmpl $0x20, %eax
je 0x6990
leaq 0x290(%rsp), %rdi
callq 0x3140
movslq 0x20c(%rsp), %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xa, %eax
jne 0x6a5d
movl 0x20c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20c(%rsp)
jmp 0x6942
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x7249
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x69f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
leaq 0x2c0(%rsp), %rdi
callq 0x31f0
leaq 0x2bf(%rsp), %rdi
callq 0x3300
jmp 0x7249
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x7225
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
leaq 0x23e(%rsp), %rdi
callq 0x11300
jmp 0x7218
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x720b
leaq 0x290(%rsp), %rdi
callq 0x3140
movslq 0x20c(%rsp), %rcx
movb (%rax,%rcx), %cl
movslq 0x208(%rsp), %rax
movb %cl, 0x210(%rsp,%rax)
movl 0x20c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x20c(%rsp)
movl 0x208(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x208(%rsp)
jmp 0x6942
movb $0x0, 0x228(%rsp)
leaq 0x200(%rsp), %rdi
leaq 0x210(%rsp), %rsi
movq $-0x1, %rdx
movl $0x30, %ecx
movl $0x31, %r8d
callq 0x11310
jmp 0x6adc
leaq 0x200(%rsp), %rdi
callq 0x110f0
movq %rax, 0xa8(%rsp)
jmp 0x6af3
movq 0xa8(%rsp), %rax
movl %eax, 0x1fc(%rsp)
movslq 0x1fc(%rsp), %rsi
leaq 0x240(%rsp), %rdi
callq 0x113a0
movq %rdx, 0x98(%rsp)
movq %rax, 0xa0(%rsp)
jmp 0x6b29
movq 0x98(%rsp), %rax
movq 0xa0(%rsp), %rcx
movq %rcx, 0x1e8(%rsp)
movq %rax, 0x1f0(%rsp)
leaq 0x1e8(%rsp), %rdi
callq 0x11400
testb $0x1, %al
jne 0x6b5c
jmp 0x6b72
movl 0x234(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x234(%rsp)
jmp 0x68e1
movslq 0x1fc(%rsp), %rsi
leaq 0x240(%rsp), %rdi
callq 0x113a0
movq %rdx, 0x88(%rsp)
movq %rax, 0x90(%rsp)
jmp 0x6b99
movq 0x88(%rsp), %rax
movq 0x90(%rsp), %rcx
movq %rcx, 0x1d8(%rsp)
movq %rax, 0x1e0(%rsp)
leaq 0x1d8(%rsp), %rdi
movl $0x1, %esi
callq 0x11430
movl 0x1fc(%rsp), %edx
movq 0x288(%rsp), %rax
movslq 0x238(%rsp), %rcx
movl %edx, (%rax,%rcx,4)
movl 0x238(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x238(%rsp)
movl 0x230(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x230(%rsp)
jmp 0x68e1
leaq 0x2f0(%rsp), %rdi
callq 0x3040
jmp 0x6c1b
callq 0x10a60
movq %rax, 0x80(%rsp)
jmp 0x6c2a
movq 0x80(%rsp), %rdi
callq 0x10b90
jmp 0x6c39
movl 0x2b4(%rsp), %esi
leaq 0x1c0(%rsp), %rdi
movl $0x1, %edx
callq 0x5a50
jmp 0x6c54
movl 0x2b4(%rsp), %esi
leaq 0x1a8(%rsp), %rdi
movl $0x2, %edx
callq 0x5a50
jmp 0x6c6f
movl $0x0, 0x1a4(%rsp)
movl $0x0, 0x1a0(%rsp)
callq 0x10a60
movq %rax, 0x78(%rsp)
jmp 0x6c91
leaq 0x17f(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x3470
movq 0x70(%rsp), %rdx
leaq 0x297d2(%rip), %rsi     # 0x30481
leaq 0x180(%rsp), %rdi
callq 0x3360
jmp 0x6cbe
movq 0x78(%rsp), %rdi
leaq 0x180(%rsp), %rsi
callq 0x10ad0
jmp 0x6cd2
leaq 0x180(%rsp), %rdi
callq 0x31f0
leaq 0x17f(%rsp), %rdi
callq 0x3300
movl $0x0, 0x178(%rsp)
movl 0x178(%rsp), %eax
movl 0x2b8(%rsp), %ecx
subl 0x234(%rsp), %ecx
cmpl %ecx, %eax
jge 0x7021
leaq 0x1c0(%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 0x6d6c
jmp 0x6ece
leaq 0x168(%rsp), %rdi
callq 0x10390
movl (%rax), %eax
movl %eax, 0x15c(%rsp)
movq 0x288(%rsp), %rax
movslq 0x178(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl 0x15c(%rsp), %ecx
xorl %ecx, %eax
movl %eax, 0x158(%rsp)
movslq 0x158(%rsp), %rsi
leaq 0x240(%rsp), %rdi
callq 0x113a0
movq %rdx, 0x60(%rsp)
movq %rax, 0x68(%rsp)
jmp 0x6dc6
movq 0x60(%rsp), %rax
movq 0x68(%rsp), %rcx
movq %rcx, 0x140(%rsp)
movq %rax, 0x148(%rsp)
leaq 0x140(%rsp), %rdi
callq 0x11400
andb $0x1, %al
movb %al, 0x157(%rsp)
testb $0x1, 0x157(%rsp)
je 0x6eba
movl 0x1a4(%rsp), %eax
incl %eax
movl %eax, 0x1a4(%rsp)
movq 0x288(%rsp), %rax
movslq 0x178(%rsp), %rcx
movl (%rax,%rcx,4), %esi
movl 0x158(%rsp), %edx
leaq 0x268(%rsp), %rdi
callq 0x10dc0
jmp 0x6e3d
jmp 0x6eba
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x71fe
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x71f1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
jmp 0x6ea8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2e8(%rsp)
movl %eax, 0x2e4(%rsp)
leaq 0x180(%rsp), %rdi
callq 0x31f0
leaq 0x17f(%rsp), %rdi
callq 0x3300
jmp 0x71f1
jmp 0x6ebc
leaq 0x168(%rsp), %rdi
callq 0x10660
jmp 0x6d4e
leaq 0x1a8(%rsp), %rax
movq %rax, 0x138(%rsp)
movq 0x138(%rsp), %rdi
callq 0x102f0
movq %rax, 0x130(%rsp)
movq 0x138(%rsp), %rdi
callq 0x10320
movq %rax, 0x128(%rsp)
leaq 0x130(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x10350
testb $0x1, %al
jne 0x6f26
jmp 0x7009
leaq 0x130(%rsp), %rdi
callq 0x10390
movl (%rax), %eax
movl %eax, 0x124(%rsp)
movq 0x288(%rsp), %rax
movslq 0x178(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movl 0x124(%rsp), %ecx
xorl %ecx, %eax
movl %eax, 0x120(%rsp)
movslq 0x120(%rsp), %rsi
leaq 0x240(%rsp), %rdi
callq 0x113a0
movq %rdx, 0x50(%rsp)
movq %rax, 0x58(%rsp)
jmp 0x6f80
movq 0x50(%rsp), %rax
movq 0x58(%rsp), %rcx
movq %rcx, 0x108(%rsp)
movq %rax, 0x110(%rsp)
leaq 0x108(%rsp), %rdi
callq 0x11400
andb $0x1, %al
movb %al, 0x11f(%rsp)
testb $0x1, 0x11f(%rsp)
je 0x6ff5
movl 0x1a0(%rsp), %eax
incl %eax
movl %eax, 0x1a0(%rsp)
movq 0x288(%rsp), %rax
movslq 0x178(%rsp), %rcx
movl (%rax,%rcx,4), %esi
movl 0x120(%rsp), %edx
leaq 0x268(%rsp), %rdi
callq 0x10dc0
jmp 0x6ff3
jmp 0x6ff5
jmp 0x6ff7
leaq 0x130(%rsp), %rdi
callq 0x10660
jmp 0x6f08
jmp 0x700b
movl 0x178(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x178(%rsp)
jmp 0x6cf7
callq 0x10a60
movq %rax, 0x48(%rsp)
jmp 0x702d
movq 0x48(%rsp), %rdi
callq 0x10b90
jmp 0x7039
movl 0x2b8(%rsp), %eax
movl %eax, 0x3c(%rsp)
movl 0x284(%rsp), %eax
movl %eax, 0x40(%rsp)
leaq 0x268(%rsp), %rdi
callq 0x10eb0
movl %eax, 0x44(%rsp)
jmp 0x7062
movl 0x3c(%rsp), %eax
movl 0x40(%rsp), %edx
movl 0x44(%rsp), %ecx
subl %edx, %ecx
addl %ecx, %eax
movl 0x234(%rsp), %ecx
subl %ecx, %eax
incl %eax
movl %eax, 0x104(%rsp)
movq 0x3cf4d(%rip), %rdi     # 0x43fd8
leaq 0x292fe(%rip), %rsi     # 0x30390
callq 0x32c0
movq %rax, 0x30(%rsp)
jmp 0x709e
movq 0x30(%rsp), %rdi
movl 0x1a4(%rsp), %esi
movl %esi, %eax
shrl $0x1f, %eax
addl %eax, %esi
sarl %esi
callq 0x3440
movq %rax, 0x28(%rsp)
jmp 0x70bf
movq 0x28(%rsp), %rdi
movq 0x3cefd(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x70d2
movq 0x3ceff(%rip), %rdi     # 0x43fd8
leaq 0x292d0(%rip), %rsi     # 0x303b0
callq 0x32c0
movq %rax, 0x20(%rsp)
jmp 0x70ec
movq 0x20(%rsp), %rdi
movl 0x1a0(%rsp), %esi
movl %esi, %eax
shrl $0x1f, %eax
addl %eax, %esi
sarl %esi
callq 0x3440
movq %rax, 0x18(%rsp)
jmp 0x710d
movq 0x18(%rsp), %rdi
movq 0x3ceaf(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x7120
movq 0x3ceb1(%rip), %rdi     # 0x43fd8
leaq 0x292a3(%rip), %rsi     # 0x303d1
callq 0x32c0
movq %rax, 0x10(%rsp)
jmp 0x713a
movq 0x10(%rsp), %rdi
movl 0x104(%rsp), %esi
callq 0x3440
movq %rax, 0x8(%rsp)
jmp 0x7152
movq 0x8(%rsp), %rdi
movq 0x3ce6a(%rip), %rsi     # 0x43fc8
callq 0x32f0
jmp 0x7165
cmpl $0x17e6, 0x104(%rsp) # imm = 0x17E6
jne 0x7174
jmp 0x7193
leaq 0x2926b(%rip), %rdi     # 0x303e6
leaq 0x29280(%rip), %rsi     # 0x30402
movl $0x152, %edx            # imm = 0x152
leaq 0x29310(%rip), %rcx     # 0x3049e
callq 0x3200
movq 0x288(%rsp), %rax
movq %rax, (%rsp)
cmpq $0x0, %rax
je 0x71ae
movq (%rsp), %rdi
callq 0x3320
leaq 0x1a8(%rsp), %rdi
callq 0x107c0
leaq 0x1c0(%rsp), %rdi
callq 0x107c0
leaq 0x240(%rsp), %rdi
callq 0x11480
leaq 0x268(%rsp), %rdi
callq 0x10ec0
leaq 0x290(%rsp), %rdi
callq 0x31f0
jmp 0x7234
leaq 0x1a8(%rsp), %rdi
callq 0x107c0
leaq 0x1c0(%rsp), %rdi
callq 0x107c0
leaq 0x240(%rsp), %rdi
callq 0x11480
leaq 0x268(%rsp), %rdi
callq 0x10ec0
leaq 0x290(%rsp), %rdi
callq 0x31f0
jmp 0x7249
leaq 0x2f0(%rsp), %rdi
callq 0x30c0
addq $0x508, %rsp            # imm = 0x508
retq
leaq 0x2f0(%rsp), %rdi
callq 0x30c0
movq 0x2e8(%rsp), %rdi
callq 0x3460
nopw %cs:(%rax,%rax)