// File: /workspace/github_cpp_makefile_star2_O3/EduBic[P]TSP-MetaheuristicSolvers/TabuSearchSolver.cpp
// Function: TabuSearchSolver::solve(TSP const&, TSPSolution const&, TSPSolution&)
bool TabuSearchSolver::solve(const TSP& tsp, const TSPSolution& initSol, TSPSolution& bestSol) {

    // clear previous use
    //mTabuList.clear();
    mTabuSet.clear();
    mAdvTabuList.clear();

    try {
        bool stop = false;
        int  iter = 0;

        //tabuList.reserve(tsp.n);
        //initTabuList(tsp.n);

        TSPSolution currSol(initSol);
        double bestValue, currValue;

        bestValue = currValue = currSol.evaluateObjectiveFunction(tsp);
        TSPMove move;

        clock_t currTime = clock();

        while (!stop) {
            iter++;

            // for small instance of problem print the current solution
            if (tsp.n < 20) {
                currSol.print(std::cout);
                std::cout << " (" << iter << ") value " << currValue << "\t(" << bestValue << ")";
            }

            //mAspiration = bestValue - currValue;

            /*double costVar;
            if (BestImprovement) {
                costVar = findBestNeighbor(tsp, currSol, move);
            } else {
                costVar = findFirstBestNeighbor(tsp, currSol, move);
            }*/

            double bestNeighValue = currValue + findBestNeighbor(tsp, currSol, move); // costVar;

            if (bestNeighValue >= tsp.infinite) {
                cout << "\tmove: NO legal neighbour" << endl;
                stop = true;
            }
            else {
                // insertTabu(move);
                if (mTabuLength != 0) {

                    // use only List
                    /*if (mTabuList.size() < mTabuLength) {
                        mTabuList.push_back(move);
                    } else {
                        mTabuList.pop_front();  // remove old elements
                        mTabuList.push_back(move);
                    }*/

                    // use only List + Set
                    if (mTabuSet.size() < mTabuLength) {
                        // get key from TSPMove
                        char buffer[50];
                        sprintf(buffer, "%u%u", move.from, move.to);
                        string moveKey = string(buffer);

                        mAdvTabuList.push_back(moveKey);
                        mTabuSet.insert(moveKey);

                    } else {
                        // get key from TSPMove
                        char buffer[50];
                        sprintf(buffer, "%u%u", move.from, move.to);
                        string moveKey = string(buffer);

                        //cout << "\tNew tabu move: " << moveKey << "\t" << mTabuSet.size() << endl;

                        // remove old key
                        string oldTabuKey = mAdvTabuList.front();

                        mAdvTabuList.pop_front();
                        mTabuSet.erase(oldTabuKey);

                        // add new key
                        mAdvTabuList.push_back(moveKey);
                        mTabuSet.insert(moveKey);
                    }

                }

                currSol = swap(currSol,move);
                currValue = bestNeighValue;

                if (currValue < bestValue - 0.01) { // TS: update incumbent (if better -with tolerance- solution found)
                    bestValue = currValue;
                    bestSol = currSol;

                    cout << " (" << iter << ") value " << currValue
                         << "\tmove: " << move.from << " , " << move.to
                         << "\tbetter solution" << std::endl;
                }

                // stopping criteria
                /*if (iter > mMaxIteration) {
                    stop = true;
                } else*/ if ((double)(clock() - currTime) / CLOCKS_PER_SEC > mMaxTime) {
                    stop = true;
                }

                //std::cout << "\tmove: " << move.from << " , " << move.to;
                //std::cout << std::endl;
            }
        }

        bestSol.iterations = iter;

        return true;
    }
    catch(std::exception& e) {
        std::cout << ">>>EXCEPTION: " << e.what() << std::endl;
        return false;
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xf8, %rsp
movq %rcx, 0x20(%rsp)
movq %rdx, %rbx
movq %rsi, %r14
movq %rdi, %r15
addq $0x48, %rdi
movq %rdi, 0x10(%rsp)
callq 0x6e9a
leaq 0x30(%r15), %r13
movq %r13, %rdi
callq 0x6f10
movq %r13, 0x38(%r15)
movq %r13, 0x30(%r15)
movq $0x0, 0x40(%r15)
leaq 0x70(%rsp), %rdi
movq %rbx, %rsi
callq 0x61ec
movq 0x70(%rsp), %rax
movq 0x78(%rsp), %rcx
subq %rax, %rcx
sarq $0x2, %rcx
decq %rcx
je 0x6465
movq 0x8(%r14), %rdx
movl (%rax), %edi
xorpd %xmm0, %xmm0
movl $0x1, %esi
movl %esi, %r8d
movslq %edi, %rdi
movslq (%rax,%r8,4), %r9
leaq (%rdi,%rdi,2), %rdi
movq (%rdx,%rdi,8), %rdi
addsd (%rdi,%r9,8), %xmm0
incl %esi
movl %r9d, %edi
cmpq %r8, %rcx
ja 0x6441
jmp 0x6469
xorpd %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
callq 0x31d0
movq %rax, 0x48(%rsp)
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
xorl %ebx, %ebx
incl %ebx
cmpl $0x13, (%r14)
jg 0x6528
leaq 0x70(%rsp), %rdi
movq 0x4b31(%rip), %rsi      # 0xafd0
callq 0x5a02
movl $0x2, %edx
movq 0x4b20(%rip), %rdi      # 0xafd0
leaq 0x1dca(%rip), %rsi      # 0x8281
callq 0x32f0
movq 0x4b0d(%rip), %rdi      # 0xafd0
movl %ebx, %esi
callq 0x3400
movq %rax, %r12
movl $0x8, %edx
movq %rax, %rdi
leaq 0x1da8(%rip), %rsi      # 0x8284
callq 0x32f0
movq %r12, %rdi
movsd 0x8(%rsp), %xmm0
callq 0x3380
movq %rax, %r12
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1e46(%rip), %rsi      # 0x8347
callq 0x32f0
movq %r12, %rdi
movsd 0x18(%rsp), %xmm0
callq 0x3380
movl $0x1, %edx
movq %rax, %rdi
leaq 0x1d6a(%rip), %rsi      # 0x828d
callq 0x32f0
movq %r15, %rdi
movq %r14, %rsi
leaq 0x70(%rsp), %rdx
movq %rsp, %rcx
callq 0x697c
movsd 0x8(%rsp), %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
ucomisd 0x20(%r14), %xmm1
jae 0x682e
movl 0x8(%r15), %eax
testq %rax, %rax
je 0x66cc
cmpq %rax, 0x70(%r15)
jae 0x65e3
movl (%rsp), %edx
movl 0x4(%rsp), %ecx
leaq 0xc0(%rsp), %r12
movq %r12, %rdi
leaq 0x1de1(%rip), %rsi      # 0x8364
xorl %eax, %eax
callq 0x3080
leaq 0x38(%rsp), %rax
movq %rax, 0x28(%rsp)
movq %r12, %rdi
callq 0x3140
leaq (%rsp,%rax), %rdx
addq $0xc0, %rdx
leaq 0x28(%rsp), %rbp
movq %rbp, %rdi
movq %r12, %rsi
callq 0x5d1c
movq %r13, %rdi
movq %rbp, %rsi
callq 0x6f4c
movq %rax, %rdi
movq %r13, %rsi
callq 0x3050
incq 0x40(%r15)
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
callq 0x6f9a
jmp 0x66b8
movl (%rsp), %edx
movl 0x4(%rsp), %ecx
leaq 0xc0(%rsp), %r12
movq %r12, %rdi
leaq 0x1d68(%rip), %rsi      # 0x8364
xorl %eax, %eax
callq 0x3080
leaq 0x38(%rsp), %rax
movq %rax, 0x28(%rsp)
movq %r12, %rdi
callq 0x3140
leaq (%rsp,%rax), %rdx
addq $0xc0, %rdx
leaq 0x28(%rsp), %rdi
movq %r12, %rsi
callq 0x5d1c
movq (%r13), %rax
leaq 0x60(%rsp), %rcx
movq %rcx, 0x50(%rsp)
movq 0x10(%rax), %rsi
movq 0x18(%rax), %rdx
addq %rsi, %rdx
leaq 0x50(%rsp), %r12
movq %r12, %rdi
callq 0x6e04
movq (%r13), %rsi
movq %r13, %rdi
callq 0x713c
movq 0x10(%rsp), %rdi
movq %r12, %rsi
callq 0x7168
movq 0x10(%rsp), %rdi
movq %rax, %rsi
callq 0x721c
movq %r13, %rdi
leaq 0x28(%rsp), %rsi
callq 0x6f4c
movq %rax, %rdi
movq %r13, %rsi
callq 0x3050
incq 0x40(%r15)
movq 0x10(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x6f9a
movq 0x50(%rsp), %rdi
leaq 0x60(%rsp), %rax
cmpq %rax, %rdi
je 0x66b8
callq 0x3290
movq 0x28(%rsp), %rdi
leaq 0x38(%rsp), %rax
cmpq %rax, %rdi
je 0x66cc
callq 0x3290
leaq 0x70(%rsp), %rsi
movq %rsp, %rdx
callq 0x6af0
movsd 0x18(%rsp), %xmm0
addsd 0x1be1(%rip), %xmm0     # 0x82c8
ucomisd 0x8(%rsp), %xmm0
jbe 0x6806
leaq 0x70(%rsp), %rax
cmpq 0x20(%rsp), %rax
je 0x672b
movq 0x20(%rsp), %rcx
movq (%rcx), %rax
movq 0x8(%rcx), %rcx
subq %rax, %rcx
je 0x672b
sarq $0x2, %rcx
movq 0x70(%rsp), %rdx
xorl %esi, %esi
movl (%rdx,%rsi,4), %edi
movl %edi, (%rax,%rsi,4)
incq %rsi
movl %esi, %edi
cmpq %rdi, %rcx
ja 0x671b
movl $0x2, %edx
movq 0x4899(%rip), %rdi      # 0xafd0
leaq 0x1b43(%rip), %rsi      # 0x8281
callq 0x32f0
movq 0x4886(%rip), %rdi      # 0xafd0
movl %ebx, %esi
callq 0x3400
movq %rax, %r12
movl $0x8, %edx
movq %rax, %rdi
leaq 0x1b21(%rip), %rsi      # 0x8284
callq 0x32f0
movq %r12, %rdi
movsd 0x8(%rsp), %xmm0
callq 0x3380
movq %rax, %r12
movl $0x7, %edx
movq %rax, %rdi
leaq 0x1be1(%rip), %rsi      # 0x8369
callq 0x32f0
movl (%rsp), %esi
movq %r12, %rdi
callq 0x3400
movq %rax, %r12
movl $0x3, %edx
movq %rax, %rdi
leaq 0x1aee(%rip), %rsi      # 0x8298
callq 0x32f0
movl 0x4(%rsp), %esi
movq %r12, %rdi
callq 0x3400
movq %rax, %r12
movl $0x10, %edx
movq %rax, %rdi
leaq 0x1ba4(%rip), %rsi      # 0x8371
callq 0x32f0
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x32b0
movsbl %al, %esi
movq %r12, %rdi
callq 0x3030
movq %rax, %rdi
callq 0x31f0
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
callq 0x31d0
subq 0x48(%rsp), %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x1810(%rip), %xmm0     # 0x8030
ucomisd 0x10(%r15), %xmm0
jbe 0x6487
jmp 0x6874
movq 0x479b(%rip), %r14      # 0xafd0
leaq 0x1b0e(%rip), %rsi      # 0x834a
movl $0x19, %edx
movq %r14, %rdi
callq 0x32f0
movq (%r14), %rax
addq -0x18(%rax), %r14
movq %r14, %rdi
movl $0xa, %esi
callq 0x32b0
movsbl %al, %esi
movq 0x4769(%rip), %rdi      # 0xafd0
callq 0x3030
movq %rax, %rdi
callq 0x31f0
movq 0x20(%rsp), %rax
movl %ebx, 0x48(%rax)
leaq 0x98(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x6892
callq 0x3290
movq 0x70(%rsp), %rdi
testq %rdi, %rdi
je 0x68a1
callq 0x3290
movb $0x1, %al
addq $0xf8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rdx, %r14
movq %rax, %rbx
jmp 0x690f
jmp 0x68ff
jmp 0x68c5
jmp 0x68ff
jmp 0x68ff
movq %rdx, %r14
movq %rax, %rbx
jmp 0x68e7
movq %rdx, %r14
movq %rax, %rbx
movq 0x50(%rsp), %rdi
leaq 0x60(%rsp), %rax
cmpq %rax, %rdi
je 0x68e7
callq 0x3290
movq 0x28(%rsp), %rdi
leaq 0x38(%rsp), %rax
cmpq %rax, %rdi
je 0x6905
callq 0x3290
jmp 0x6905
jmp 0x68ff
movq %rdx, %r14
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x62c2
cmpl $0x1, %r14d
jne 0x696c
movq %rbx, %rdi
callq 0x3130
movq %rax, %rbx
movq 0x46a9(%rip), %rdi      # 0xafd0
leaq 0x196e(%rip), %rsi      # 0x829c
movl $0xe, %edx
callq 0x32f0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movq 0x4688(%rip), %rdi      # 0xafd0
movq %rax, %rsi
callq 0x32c0
movq %rax, %rdi
callq 0x3150
callq 0x33c0
xorl %eax, %eax
jmp 0x68a3
movq %rax, %rbx
callq 0x33c0
movq %rbx, %rdi
callq 0x3410
movq %rax, %rdi
callq 0x62e8