// File: estan[P]tsp/tsp.cpp
// Function: twoOpt(std::vector<unsigned short, std::allocator<unsigned short>>&, Matrix<unsigned int> const&, Matrix<unsigned short> const&, std::vector<unsigned short, std::allocator<unsigned short>>&, unsigned int&, unsigned int)
inline void twoOpt(vector<uint16_t>& tour, const Matrix<uint32_t>& d,
        const Matrix<uint16_t>& neighbor, vector<uint16_t> &position,
        uint32_t& max, uint32_t min) {
    size_t N = d.rows(); // Number of cities.

    // Candidate edges uv, wz and their positions in tour.
    uint16_t u, v, w, z;
    size_t u_i, v_i, w_i, z_i;

    bool locallyOptimal = false;
    while (!locallyOptimal) {
        locallyOptimal = true;

        // For each edge uv.
        for (u_i = 0, v_i = 1; u_i < N; ++u_i, ++v_i) {
            u = tour[u_i];
            v = tour[v_i % N];

            // For each edge wz (w k:th closest neighbor of u).
            for (size_t k = 0; k < neighbor.cols(); ++k) {
                w_i = position[neighbor[u][k]];
                z_i = w_i + 1;
                w = tour[w_i];
                z = tour[z_i % N];

                if (v == w || z == u) {
                    continue; // Skip adjacent edges.
                }

                // d[u][w] + min is a lower bound on new length.
                // d[u][v] + max is an upper bound on old length.
                if (d[u][w] + min > d[u][v] + max) {
                    break; // Go to next edge uv.
                }

                if (d[u][w] + d[v][z] < d[u][v] + d[w][z]) {
                    //   --u w--        --u-w->
                    //      X     ===>
                    //   <-z v->        <-z-v--
                    reverse(tour, v_i % N, w_i, position);
                    max = maximum(max, d[u][w], d[v][z]);
                    locallyOptimal = false;
                    break;
                }
            }
        }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movl %r9d, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
callq 0x3630
movq %rax, -0x38(%rbp)
movb $0x0, -0x61(%rbp)
movb -0x61(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x68e2
jmp 0x6b73
movb $0x1, -0x61(%rbp)
movq $0x0, -0x48(%rbp)
movq $0x1, -0x50(%rbp)
movq -0x48(%rbp), %rax
cmpq -0x38(%rbp), %rax
jae 0x6b6e
movq -0x8(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x3ad0
movw (%rax), %ax
movw %ax, -0x3a(%rbp)
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rax
xorl %ecx, %ecx
movl %ecx, %edx
divq -0x38(%rbp)
movq %rdx, %rsi
callq 0x3ad0
movw (%rax), %ax
movw %ax, -0x3c(%rbp)
movq $0x0, -0x70(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x18(%rbp), %rdi
callq 0x9030
movq %rax, %rcx
movq -0x78(%rbp), %rax
cmpq %rcx, %rax
jae 0x6b4f
movq -0x20(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x18(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x9050
movq -0x80(%rbp), %rdi
movq -0x70(%rbp), %rcx
movzwl (%rax,%rcx,2), %eax
movl %eax, %esi
callq 0x3ad0
movzwl (%rax), %eax
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movq -0x58(%rbp), %rsi
callq 0x3ad0
movw (%rax), %ax
movw %ax, -0x3e(%rbp)
movq -0x8(%rbp), %rdi
movq -0x60(%rbp), %rax
xorl %ecx, %ecx
movl %ecx, %edx
divq -0x38(%rbp)
movq %rdx, %rsi
callq 0x3ad0
movw (%rax), %ax
movw %ax, -0x40(%rbp)
movzwl -0x3c(%rbp), %eax
movzwl -0x3e(%rbp), %ecx
cmpl %ecx, %eax
je 0x69e6
movzwl -0x40(%rbp), %eax
movzwl -0x3a(%rbp), %ecx
cmpl %ecx, %eax
jne 0x69eb
jmp 0x6b3e
movq -0x10(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x36a0
movzwl -0x3e(%rbp), %ecx
movl (%rax,%rcx,4), %eax
addl -0x2c(%rbp), %eax
movl %eax, -0x84(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x36a0
movq %rax, %rcx
movl -0x84(%rbp), %eax
movzwl -0x3c(%rbp), %edx
movl (%rcx,%rdx,4), %ecx
movq -0x28(%rbp), %rdx
addl (%rdx), %ecx
cmpl %ecx, %eax
jbe 0x6a34
jmp 0x6b4f
movq -0x10(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x36a0
movzwl -0x3e(%rbp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, -0x90(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3c(%rbp), %esi
callq 0x36a0
movq %rax, %rcx
movl -0x90(%rbp), %eax
movzwl -0x40(%rbp), %edx
addl (%rcx,%rdx,4), %eax
movl %eax, -0x88(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x36a0
movzwl -0x3c(%rbp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, -0x8c(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3e(%rbp), %esi
callq 0x36a0
movl -0x8c(%rbp), %ecx
movq %rax, %rdx
movl -0x88(%rbp), %eax
movzwl -0x40(%rbp), %esi
addl (%rdx,%rsi,4), %ecx
cmpl %ecx, %eax
jae 0x6b3c
movq -0x8(%rbp), %rdi
movq -0x50(%rbp), %rax
xorl %ecx, %ecx
movl %ecx, %edx
divq -0x38(%rbp)
movq %rdx, %rsi
movq -0x58(%rbp), %rdx
movq -0x20(%rbp), %rcx
callq 0x9080
movq -0x28(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3a(%rbp), %esi
callq 0x36a0
movzwl -0x3e(%rbp), %ecx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
movzwl -0x3c(%rbp), %esi
callq 0x36a0
movq -0xa0(%rbp), %rdi
movq -0x98(%rbp), %rsi
movq %rax, %rdx
movzwl -0x40(%rbp), %eax
shlq $0x2, %rax
addq %rax, %rdx
callq 0x3470
movl %eax, %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movb $0x0, -0x61(%rbp)
jmp 0x6b4f
jmp 0x6b3e
movq -0x70(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x70(%rbp)
jmp 0x693f
jmp 0x6b51
movq -0x48(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0x68f6
jmp 0x68d4
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax)