// File: Manca[P]algorithms2/./assignment5.hpp
// Function: assignment5::TSP::solve()
float solve()
        {
            if (num_cities == 0)
                return 0.0;
            ////// array definition
            PROFILE("Allocation");
            int S_size = (int)std::pow(2, num_cities-1); // 2^24 (first city is always included)
            float **A = new float*[S_size];
            for (int i = 0; i < S_size; i++)
            {
                A[i] = new float[num_cities];         // 2^24 x 24
            }
            PROFILE_STOP();
            PROFILE("Initialization");
            // initialization
            for (int i = 0; i < S_size; i++)
            {
                for (int j = 0; j < num_cities;j++)
                    A[i][j] = (float)INT32_MAX;
            }
            A[0][0] = 0;    // first subset of S (subset 1), contains only starting vertex 0 (0...001)
            PROFILE_STOP();
            // algo
            for (int m = 1; m < num_cities; m++)    // we need to start from 1 to get all the cities that are connected to city 0 directly!
            {
                PROFILE("Processing m = " + std::to_string(m));
                int S = (1 << m) - 1;    // we begin with initial number of ones (m=2) (2^m - 1 - init size of the set)
                int S_no_j = 0;         // previous S that does not contain j

                while (S < (1 << (num_cities-1)))   // and generate all subsets with m ones in them until we hit 2^(num_cities-1)
                {
                    // let's find all the ones in S and use their positions as vertex numbers
                  //  std::cout << "Subset: " << S << std::endl << "------" << std::endl;
                    for (int j = 0; j < num_cities-1; j++)      // for each city, see if it's in S, and yes do the math! (j+1 actual city number!)
                    {
                        int sXORj = S ^ (1 << j);               // S xor 2^j (put 1 at j's position)
                        // extract last bit
                        bool isJinS = !((sXORj >> j) & 1);      // get the xor'ed bit and AND it with 1 to see if it's 1 or 0
                        if (isJinS)
                        {
                            // do work
                           // std::cout << "Processing city j: " << j+1 << std::endl;
                            float min = (float)INT32_MAX;

                            S_no_j = S ^ (1 << j);
                            std::vector<float> dists(num_cities, (float)INT32_MAX);   // distances
                            dists[0] = A[S_no_j][0] + _distances[0][j+1];

                            for (int k = 0; k < num_cities-1; k++)
                            {
                                if (k != j)
                                {
                                    // need to check if k is in S!
                                    int sXORk = S ^ (1 << k);  // S xor 2^k (put 1 at k's position)
                                    bool isKinS = !((sXORk >> k) & 1);
                                    if (isKinS)
                                    {
                                  //      std::cout << "S without j is: " << S_no_j << std::endl;
                                        dists[k+1] = A[S_no_j][k+1] + _distances[k+1][j+1];
                                    }
                                }
                            }
                            // find min
                            for (int i = 0; i < num_cities; i++)
                                if (dists[i] < min)
                                    min = dists[i];
                           // std::cout << "Minimum for subset: " << S << " is: " << min << std::endl << "-----" << std::endl;
                            A[S][j+1] = min;
                        }
                    }
                    // use Gosper Hack to get the next subset
                    S = next_subset(S);
                }
                PROFILE_STOP();
            }

            // finally, let's get the minimum of all minimums
            float min_min = (float)INT32_MAX;
            for (int j = 1; j < num_cities; j++)
            {
                float calc = A[S_size-1][j] + _distances[j][0];
                if (calc < min_min)
                    min_min = calc;
            }
            std::cout << "Minimum cost tour is: " << (int)min_min << std::endl;
            assert((int)min_min == 26442);
            // cleanup
            PROFILE("Cleanup")
            for (int i = 0; i < S_size; i++)
            {
                delete[] A[i];
            }
            delete[] A;
            PROFILE_STOP();

            return min_min;
        }

// Assembly:
subq $0x1c8, %rsp            # imm = 0x1C8
movq %rdi, 0x1b8(%rsp)
movq 0x1b8(%rsp), %rax
movq %rax, 0x78(%rsp)
cmpl $0x0, (%rax)
jne 0x12ac2
xorps %xmm0, %xmm0
movss %xmm0, 0x1c4(%rsp)
jmp 0x134fd
callq 0x10a60
movq %rax, 0x68(%rsp)
leaq 0x197(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x3470
movq 0x70(%rsp), %rdx
leaq 0x1e24a(%rip), %rsi     # 0x30d34
leaq 0x198(%rsp), %rdi
callq 0x3360
jmp 0x12af9
movq 0x68(%rsp), %rdi
leaq 0x198(%rsp), %rsi
callq 0x10ad0
jmp 0x12b0d
leaq 0x198(%rsp), %rdi
callq 0x31f0
leaq 0x197(%rsp), %rdi
callq 0x3300
movq 0x78(%rsp), %rax
movl (%rax), %esi
subl $0x1, %esi
movl $0x2, %edi
callq 0x10ff0
cvttsd2si %xmm0, %eax
movl %eax, 0x180(%rsp)
movslq 0x180(%rsp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, 0x178(%rsp)
movl $0x0, 0x174(%rsp)
movl 0x174(%rsp), %eax
cmpl 0x180(%rsp), %eax
jge 0x12c32
movq 0x78(%rsp), %rax
movslq (%rax), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, %rdx
movq 0x178(%rsp), %rax
movslq 0x174(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movl 0x174(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x174(%rsp)
jmp 0x12b82
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
jmp 0x12c20
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
leaq 0x198(%rsp), %rdi
callq 0x31f0
leaq 0x197(%rsp), %rdi
callq 0x3300
jmp 0x1350e
callq 0x10a60
movq %rax, %rdi
callq 0x10b90
callq 0x10a60
movq %rax, 0x58(%rsp)
leaq 0x14f(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x3470
movq 0x60(%rsp), %rdx
leaq 0x1e0d8(%rip), %rsi     # 0x30d3f
leaq 0x150(%rsp), %rdi
callq 0x3360
jmp 0x12c76
movq 0x58(%rsp), %rdi
leaq 0x150(%rsp), %rsi
callq 0x10ad0
jmp 0x12c8a
leaq 0x150(%rsp), %rdi
callq 0x31f0
leaq 0x14f(%rsp), %rdi
callq 0x3300
movl $0x0, 0x148(%rsp)
movl 0x148(%rsp), %eax
cmpl 0x180(%rsp), %eax
jge 0x12d7f
movl $0x0, 0x144(%rsp)
movq 0x78(%rsp), %rcx
movl 0x144(%rsp), %eax
cmpl (%rcx), %eax
jge 0x12d67
movq 0x178(%rsp), %rax
movslq 0x148(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x144(%rsp), %rcx
movss 0x1d30a(%rip), %xmm0    # 0x30010
movss %xmm0, (%rax,%rcx,4)
movl 0x144(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x144(%rsp)
jmp 0x12cce
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
jmp 0x12d55
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
leaq 0x150(%rsp), %rdi
callq 0x31f0
leaq 0x14f(%rsp), %rdi
callq 0x3300
jmp 0x1350e
jmp 0x12d69
movl 0x148(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x148(%rsp)
jmp 0x12caf
movq 0x178(%rsp), %rax
movq (%rax), %rax
xorps %xmm0, %xmm0
movss %xmm0, (%rax)
callq 0x10a60
movq %rax, %rdi
callq 0x10b90
movl $0x1, 0x140(%rsp)
movq 0x78(%rsp), %rcx
movl 0x140(%rsp), %eax
cmpl (%rcx), %eax
jge 0x13285
callq 0x10a60
movq %rax, 0x48(%rsp)
movl 0x140(%rsp), %esi
leaq 0x100(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x1b7a0
movq 0x50(%rsp), %rdx
leaq 0x1df62(%rip), %rsi     # 0x30d4e
leaq 0x120(%rsp), %rdi
callq 0x1b750
jmp 0x12dfb
movq 0x48(%rsp), %rdi
leaq 0x120(%rsp), %rsi
callq 0x10ad0
jmp 0x12e0f
leaq 0x120(%rsp), %rdi
callq 0x31f0
leaq 0x100(%rsp), %rdi
callq 0x31f0
movl 0x140(%rsp), %ecx
movl $0x1, %eax
shll %cl, %eax
subl $0x1, %eax
movl %eax, 0xfc(%rsp)
movl $0x0, 0xf8(%rsp)
movq 0x78(%rsp), %rcx
movl 0xfc(%rsp), %eax
movl (%rcx), %ecx
subl $0x1, %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
cmpl %ecx, %eax
jge 0x13262
movl $0x0, 0xf4(%rsp)
movq 0x78(%rsp), %rcx
movl 0xf4(%rsp), %eax
movl (%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x13245
movl 0xfc(%rsp), %eax
movl 0xf4(%rsp), %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
xorl %ecx, %eax
movl %eax, 0xf0(%rsp)
movl 0xf0(%rsp), %eax
movl 0xf4(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
andb $0x1, %al
movb %al, 0xef(%rsp)
testb $0x1, 0xef(%rsp)
je 0x1322d
movq 0x78(%rsp), %rax
movl $0x4f000000, 0xe8(%rsp) # imm = 0x4F000000
movl 0xfc(%rsp), %ecx
movb 0xf4(%rsp), %sil
movb %sil, %dl
btcl %edx, %ecx
movl %ecx, 0xf8(%rsp)
movslq (%rax), %rax
movq %rax, 0x38(%rsp)
movl $0x4f000000, 0xcc(%rsp) # imm = 0x4F000000
leaq 0xcb(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x1b8e0
movq 0x38(%rsp), %rsi
movq 0x40(%rsp), %rcx
leaq 0xd0(%rsp), %rdi
leaq 0xcc(%rsp), %rdx
callq 0x1b8f0
jmp 0x12f56
leaq 0xcb(%rsp), %rdi
callq 0x1b970
movq 0x78(%rsp), %rdi
movq 0x178(%rsp), %rax
movslq 0xf8(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movss (%rax), %xmm0
movss %xmm0, 0x30(%rsp)
addq $0x20, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x19170
movq %rax, %rdi
movl 0xf4(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rsi
callq 0x1b5b0
movss 0x30(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, 0x34(%rsp)
leaq 0xd0(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1b5b0
movss 0x34(%rsp), %xmm0
movss %xmm0, (%rax)
movl $0x0, 0xc4(%rsp)
movq 0x78(%rsp), %rcx
movl 0xc4(%rsp), %eax
movl (%rcx), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x13178
movl 0xc4(%rsp), %eax
cmpl 0xf4(%rsp), %eax
je 0x13160
movl 0xfc(%rsp), %eax
movl 0xc4(%rsp), %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
xorl %ecx, %eax
movl %eax, 0xc0(%rsp)
movl 0xc0(%rsp), %eax
movl 0xc4(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
andb $0x1, %al
movb %al, 0xbf(%rsp)
testb $0x1, 0xbf(%rsp)
je 0x1315e
movq 0x78(%rsp), %rdi
movq 0x178(%rsp), %rax
movslq 0xf8(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movl 0xc4(%rsp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movss (%rax,%rcx,4), %xmm0
movss %xmm0, 0x28(%rsp)
addq $0x20, %rdi
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rsi
callq 0x19170
movq %rax, %rdi
movl 0xf4(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rsi
callq 0x1b5b0
movss 0x28(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, 0x2c(%rsp)
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movslq %eax, %rsi
leaq 0xd0(%rsp), %rdi
callq 0x1b5b0
movss 0x2c(%rsp), %xmm0
movss %xmm0, (%rax)
jmp 0x1315e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
jmp 0x13126
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
leaq 0x120(%rsp), %rdi
callq 0x31f0
leaq 0x100(%rsp), %rdi
callq 0x31f0
jmp 0x1350e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
leaq 0xcb(%rsp), %rdi
callq 0x1b970
jmp 0x1350e
jmp 0x13160
jmp 0x13162
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x12fde
movl $0x0, 0xb8(%rsp)
movq 0x78(%rsp), %rcx
movl 0xb8(%rsp), %eax
cmpl (%rcx), %eax
jge 0x131f1
movslq 0xb8(%rsp), %rsi
leaq 0xd0(%rsp), %rdi
callq 0x1b5b0
movss (%rax), %xmm1
movss 0xe8(%rsp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x131dc
movslq 0xb8(%rsp), %rsi
leaq 0xd0(%rsp), %rdi
callq 0x1b5b0
movss (%rax), %xmm0
movss %xmm0, 0xe8(%rsp)
jmp 0x131de
movl 0xb8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb8(%rsp)
jmp 0x13183
movss 0xe8(%rsp), %xmm0
movq 0x178(%rsp), %rax
movslq 0xfc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movl 0xf4(%rsp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movss %xmm0, (%rax,%rcx,4)
leaq 0xd0(%rsp), %rdi
callq 0x1a5b0
jmp 0x1322f
movl 0xf4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xf4(%rsp)
jmp 0x12e79
movq 0x78(%rsp), %rdi
movl 0xfc(%rsp), %esi
callq 0x1b980
movl %eax, 0xfc(%rsp)
jmp 0x12e4c
callq 0x10a60
movq %rax, %rdi
callq 0x10b90
movl 0x140(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x140(%rsp)
jmp 0x12da9
movss 0x1cd83(%rip), %xmm0    # 0x30010
movss %xmm0, 0xb4(%rsp)
movl $0x1, 0xb0(%rsp)
movq 0x78(%rsp), %rcx
movl 0xb0(%rsp), %eax
cmpl (%rcx), %eax
jge 0x13357
movq 0x78(%rsp), %rdi
movq 0x178(%rsp), %rax
movl 0x180(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movslq 0xb0(%rsp), %rcx
movss (%rax,%rcx,4), %xmm0
movss %xmm0, 0x24(%rsp)
addq $0x20, %rdi
movslq 0xb0(%rsp), %rsi
callq 0x19170
movq %rax, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1b5b0
movss 0x24(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, 0xac(%rsp)
movss 0xac(%rsp), %xmm1
movss 0xb4(%rsp), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x1333f
movss 0xac(%rsp), %xmm0
movss %xmm0, 0xb4(%rsp)
jmp 0x13341
movl 0xb0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb0(%rsp)
jmp 0x132a1
movq 0x30c7a(%rip), %rdi     # 0x43fd8
leaq 0x1d9f9(%rip), %rsi     # 0x30d5e
callq 0x32c0
movq %rax, %rdi
cvttss2si 0xb4(%rsp), %esi
callq 0x3440
movq %rax, %rdi
movq 0x30c43(%rip), %rsi     # 0x43fc8
callq 0x32f0
cvttss2si 0xb4(%rsp), %eax
cmpl $0x674a, %eax           # imm = 0x674A
jne 0x1339c
jmp 0x133bb
leaq 0x1d9d2(%rip), %rdi     # 0x30d75
leaq 0x1d9e1(%rip), %rsi     # 0x30d8b
movl $0xa6, %edx
leaq 0x1d9e7(%rip), %rcx     # 0x30d9d
callq 0x3200
callq 0x10a60
movq %rax, 0x10(%rsp)
leaq 0x87(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x3470
movq 0x18(%rsp), %rdx
leaq 0x1d9da(%rip), %rsi     # 0x30dbd
leaq 0x88(%rsp), %rdi
callq 0x3360
jmp 0x133f2
movq 0x10(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x10ad0
jmp 0x13406
leaq 0x88(%rsp), %rdi
callq 0x31f0
leaq 0x87(%rsp), %rdi
callq 0x3300
movl $0x0, 0x80(%rsp)
movl 0x80(%rsp), %eax
cmpl 0x180(%rsp), %eax
jge 0x134c3
movq 0x178(%rsp), %rax
movslq 0x80(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x13468
movq 0x8(%rsp), %rdi
callq 0x3320
jmp 0x1346a
movl 0x80(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x80(%rsp)
jmp 0x1342b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
jmp 0x134b4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x188(%rsp)
movl %eax, 0x184(%rsp)
leaq 0x88(%rsp), %rdi
callq 0x31f0
leaq 0x87(%rsp), %rdi
callq 0x3300
jmp 0x1350e
movq 0x178(%rsp), %rax
movq %rax, (%rsp)
cmpq $0x0, %rax
je 0x134de
movq (%rsp), %rdi
callq 0x3320
callq 0x10a60
movq %rax, %rdi
callq 0x10b90
movss 0xb4(%rsp), %xmm0
movss %xmm0, 0x1c4(%rsp)
movss 0x1c4(%rsp), %xmm0
addq $0x1c8, %rsp            # imm = 0x1C8
retq
movq 0x188(%rsp), %rdi
callq 0x3460
nopl (%rax,%rax)