// File: /workspace/github_cpp_makefile_star2_O2/estan[P]tsp/tsp.cpp
// Function: std::vector<unsigned short, std::allocator<unsigned short>> approximate<std::chrono::_V2::system_clock>(std::istream&, std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::_V2::system_clock::duration> const&)
vector<uint16_t> approximate(istream &in, const chrono::time_point<T>& deadline) {
    /*
     * Initialization.
     */

    // Deadline for 3-opt inside main loop is 50 ms before hard deadline.
    chrono::milliseconds fifty_ms(50);
    auto threeOptDeadline = deadline - fifty_ms;

    // Calculate distance / K-nearest neighbors matrix.
    const Matrix<uint32_t> d = createDistanceMatrix(in);
    const Matrix<uint16_t> neighbor = createNeighborsMatrix(d, MAX_K);
    const uint32_t min = minDistance(d); // Shortest distance.
    const size_t N = d.rows();           // Number of cities.

    // Generate initial greedy tour.
    vector<uint16_t> tour = greedy(d);

    // Create max / position for initial 2-opt + 3-opt.
    vector<uint16_t> position(N);
    uint32_t max = 0;
    for (uint16_t i = 0; i < N; ++i) {
        max = std::max(max, d[i][(i + 1) % N]); // Maximum distance in tour.
        position[tour[i]] = i;                  // tour[i] is i:th city in tour.
    }

    /*
     * Main loop.
     *
     * We repeatedly
     *
     *   1) Optimize the tour with 2-opt + 3-opt.
     *   2) "Kick" the tour with a random 4-exchange.
     *
     * until only max(50, 2 * average iteration time) milliseconds remains
     * before deadline, and then pick the shortest tour we found.
     */

    // Some main loop statistics.
    size_t i = 0;                        // Number of iterations of main loop.
    chrono::milliseconds totalTime(0);   // Total time spent in main loop.
    chrono::milliseconds averageTime(0); // Average main loop iteration time.

    vector<uint16_t> shortestTour = tour;          // Best tour found.
    uint64_t shortestTourLength = length(tour, d); // Length of best tour found.

    for (i = 0; (now() + std::max(fifty_ms, 2 * averageTime)) < deadline; ++i) {
        auto start = now();

        // Optimize tour with 2-opt + 3-opt.
        twoOpt(tour, d, neighbor, position, max, min);
        threeOpt(tour, d, neighbor, position, max, min, threeOptDeadline);

        uint64_t tourLength = length(tour, d);
        if (tourLength < shortestTourLength) {
            // Shorter tour found.
            shortestTour = tour;
            shortestTourLength = tourLength;
        }

        if (N >= 8) {
            // Perform random 4-opt "double bridge" move.
            tour = doubleBridge(tour);
        } else {
            // Tiny tour, so just shuffle it instead.
            shuffle(tour.begin(), tour.end(), rng);
        }

        // Update max / position needed by fast 2/3-opt.
        max = 0;
        for (uint16_t j = 0; j < N; ++j) {
            max = std::max(max, d[tour[j]][tour[(j + 1) % N]]);
            position[tour[j]] = j;
        }

        // Collect statistics.
        totalTime += chrono::duration_cast<chrono::milliseconds>(now() - start);
        averageTime = totalTime / (i + 1);
    }

    LOG("Main Loop Statistics");
    LOG("  iterations: " << i);
    LOG("  totalTime: " << totalTime);
    LOG("  averageTime: " << averageTime);

    return shortestTour;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xe8, %rsp
movq %rdi, 0x10(%rsp)
movq $-0x2faf080, %rax       # imm = 0xFD050F80
movq %rdx, 0x48(%rsp)
addq (%rdx), %rax
movq %rax, 0x78(%rsp)
leaq 0x80(%rsp), %rbx
movq %rbx, %rdi
callq 0x1362
leaq 0xa8(%rsp), %rdi
pushq $0x14
popq %rdx
movq %rbx, %rsi
callq 0x151d
leaq 0x80(%rsp), %rbx
movq %rbx, %rdi
callq 0x131c
movl %eax, %ebp
movq 0x18(%rbx), %r15
leaq 0x20(%rsp), %rdi
movq %rbx, %rsi
callq 0x2128
leaq 0x60(%rsp), %rdi
leaq 0xd0(%rsp), %rdx
movq %r15, %rsi
callq 0x1a12
andl $0x0, 0xc(%rsp)
movq 0x80(%rsp), %rax
movq 0xa0(%rsp), %rcx
movq 0x20(%rsp), %rdx
xorl %esi, %esi
movq 0x60(%rsp), %rdi
xorl %r8d, %r8d
xorl %r9d, %r9d
movzwl %r9w, %r10d
cmpq %r10, %r15
jbe 0x1b4c
movq %rcx, %r11
imulq %r10, %r11
leaq (%rax,%r11,4), %r11
leaq 0x1(%r10), %rbx
cmpq %r15, %rbx
cmovel %esi, %ebx
movl (%r11,%rbx,4), %r11d
cmpl %r11d, %r8d
cmovbel %r11d, %r8d
movl %r8d, 0xc(%rsp)
movzwl (%rdx,%r10,2), %r10d
movw %r9w, (%rdi,%r10,2)
incl %r9d
jmp 0x1b0f
movl %ebp, 0x1c(%rsp)
leaq 0x20(%rsp), %rsi
movq 0x10(%rsp), %rdi
callq 0x224e
leaq 0x20(%rsp), %rdi
leaq 0x80(%rsp), %rsi
movq %rdi, %r12
movq %rsi, %r14
callq 0x229a
movq %rax, 0x38(%rsp)
leaq 0xc(%rsp), %rbx
xorl %ebp, %ebp
xorl %r13d, %r13d
movq $0x0, 0x40(%rsp)
callq 0x1030
addq %rbp, %rbp
cmpq $0x33, %rbp
pushq $0x32
popq %rcx
cmovlq %rcx, %rbp
imulq $0xf4240, %rbp, %rcx    # imm = 0xF4240
addq %rax, %rcx
movq 0x48(%rsp), %rax
cmpq (%rax), %rcx
jge 0x1d3e
movq %r13, 0x58(%rsp)
callq 0x1030
movq %rax, 0x50(%rsp)
movq %r12, %rdi
movq %r14, %r12
movq %r14, %rsi
movl 0x1c(%rsp), %ebp
leaq 0xa8(%rsp), %r14
movq %r14, %rdx
leaq 0x60(%rsp), %r13
movq %r13, %rcx
movq %rbx, %r8
movl %ebp, %r9d
callq 0x22f6
leaq 0x78(%rsp), %rax
movq %rax, (%rsp)
leaq 0x20(%rsp), %rdi
movq %r12, %rsi
movq %r14, %rdx
movq %r13, %rcx
movq %rbx, %r8
movl %ebp, %r9d
callq 0x2506
leaq 0x20(%rsp), %rdi
movq %rdi, %r13
movq %r12, %rbx
movq %r12, %rsi
callq 0x229a
cmpq 0x38(%rsp), %rax
leaq 0xd0(%rsp), %rbp
movl $0x0, %r12d
jae 0x1c53
movq %rax, %r14
movq 0x10(%rsp), %rdi
movq %r13, %rsi
callq 0x2cd6
movq %r14, 0x38(%rsp)
cmpq $0x8, %r15
jb 0x1c7c
movq %rbp, %rdi
movq %r13, %r14
movq %r13, %rsi
callq 0x2d96
movq %r14, %rdi
movq %rbp, %rsi
callq 0x3550
movq %rbp, %rdi
callq 0x2066
jmp 0x1c92
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
leaq 0x67f3(%rip), %rdx      # 0x8480
callq 0x2e8f
andl $0x0, 0xc(%rsp)
movq 0x20(%rsp), %rax
movq 0x80(%rsp), %rcx
movq 0xa0(%rsp), %rdx
xorl %esi, %esi
movq 0x60(%rsp), %rdi
xorl %r8d, %r8d
movq %r13, %rbp
movq %rbx, %r14
leaq 0xc(%rsp), %rbx
movq 0x58(%rsp), %r13
movzwl %r8w, %r9d
cmpq %r9, %r15
jbe 0x1d07
movzwl (%rax,%r9,2), %r10d
movq %rdx, %r11
imulq %r10, %r11
leaq (%rcx,%r11,4), %r11
incq %r9
cmpq %r15, %r9
cmovel %r12d, %r9d
movzwl (%rax,%r9,2), %r9d
movl (%r11,%r9,4), %r9d
cmpl %r9d, %esi
cmovbel %r9d, %esi
movl %esi, 0xc(%rsp)
movw %r8w, (%rdi,%r10,2)
incl %r8d
jmp 0x1cc6
movq %rbp, %r12
callq 0x1030
subq 0x50(%rsp), %rax
cqto
movl $0xf4240, %ecx          # imm = 0xF4240
idivq %rcx
addq %rax, %r13
movq 0x40(%rsp), %rsi
incq %rsi
movq %r13, %rax
xorl %edx, %edx
movq %rsi, 0x40(%rsp)
divq %rsi
movq %rax, %rbp
jmp 0x1b8f
leaq 0x60(%rsp), %rdi
callq 0x2066
leaq 0x20(%rsp), %rdi
callq 0x2066
leaq 0xa8(%rsp), %rdi
callq 0x2066
leaq 0x80(%rsp), %rdi
callq 0x1dea
movq 0x10(%rsp), %rax
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
jmp 0x1da8
movq %rax, %rbx
jmp 0x1db2
movq %rax, %rbx
jmp 0x1dbc
movq %rax, %rbx
jmp 0x1dc9
jmp 0x1d9b
jmp 0x1d9b
movq %rax, %rbx
movq 0x10(%rsp), %rdi
callq 0x2066
leaq 0x60(%rsp), %rdi
callq 0x2066
leaq 0x20(%rsp), %rdi
callq 0x2066
leaq 0xa8(%rsp), %rdi
callq 0x2066
leaq 0x80(%rsp), %rdi
callq 0x1dea
movq %rbx, %rdi
callq 0x1190