// File: /workspace/github_cpp_makefile_star2_O1/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 $0x108, %rsp            # imm = 0x108
movq %rcx, 0x30(%rsp)
movq %rdx, %rbx
movq %rsi, %r14
movq %rdi, %r15
addq $0x48, %rdi
movq %rdi, 0x10(%rsp)
callq 0x6fba
leaq 0x30(%r15), %r12
movq %r12, %rdi
callq 0x7030
movq %r12, 0x38(%r15)
movq %r12, 0x30(%r15)
movq $0x0, 0x40(%r15)
leaq 0x80(%rsp), %rdi
movq %rbx, %rsi
callq 0x625a
movq 0x80(%rsp), %rax
movq 0x88(%rsp), %rcx
subq %rax, %rcx
sarq $0x2, %rcx
decq %rcx
movq %r12, 0x18(%rsp)
je 0x64dd
movq 0x8(%r14), %rdx
xorpd %xmm0, %xmm0
xorl %esi, %esi
movslq (%rax,%rsi,4), %rdi
incq %rsi
movl %esi, %r8d
movslq (%rax,%r8,4), %r9
leaq (%rdi,%rdi,2), %rdi
movq (%rdx,%rdi,8), %rdi
addsd (%rdi,%r9,8), %xmm0
cmpq %r8, %rcx
ja 0x64ba
jmp 0x64e1
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
callq 0x31d0
movq %rax, 0x58(%rsp)
xorl %r13d, %r13d
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
xorl %r12d, %r12d
incl %r12d
cmpl $0x13, (%r14)
jg 0x65a9
leaq 0x80(%rsp), %rdi
movq 0x4ab1(%rip), %rsi      # 0xafd0
callq 0x5a76
movl $0x2, %edx
movq 0x4aa0(%rip), %rdi      # 0xafd0
leaq 0x1d6a(%rip), %rsi      # 0x82a1
callq 0x32f0
movq 0x4a8d(%rip), %rdi      # 0xafd0
movl %r12d, %esi
callq 0x3400
movq %rax, %rbp
movl $0x8, %edx
movq %rax, %rdi
leaq 0x1d47(%rip), %rsi      # 0x82a4
callq 0x32f0
movq %rbp, %rdi
movsd 0x28(%rsp), %xmm0
callq 0x3380
movq %rax, %rbp
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1de5(%rip), %rsi      # 0x8367
callq 0x32f0
movq %rbp, %rdi
movsd 0x20(%rsp), %xmm0
callq 0x3380
movl $0x1, %edx
movq %rax, %rdi
leaq 0x1d09(%rip), %rsi      # 0x82ad
callq 0x32f0
movq %r15, %rdi
movq %r14, %rsi
leaq 0x80(%rsp), %rdx
movq %rsp, %rcx
callq 0x6a3c
addsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
ucomisd 0x20(%r14), %xmm0
jae 0x666c
movl 0x8(%r15), %eax
testq %rax, %rax
je 0x67b0
cmpq %rax, 0x70(%r15)
jae 0x66be
movl (%rsp), %edx
movl 0x4(%rsp), %ecx
leaq 0xd0(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1d7d(%rip), %rsi      # 0x8384
xorl %eax, %eax
callq 0x3080
leaq 0x48(%rsp), %rax
movq %rax, 0x38(%rsp)
movq %rbp, %rdi
callq 0x3140
leaq (%rsp,%rax), %rdx
addq $0xd0, %rdx
leaq 0x38(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x5d90
movq 0x18(%rsp), %rbp
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x706c
movq %rax, %rdi
movq %rbp, %rsi
callq 0x3050
incq 0x40(%r15)
movq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0x70ba
jmp 0x679c
movl $0x19, %edx
movq 0x4958(%rip), %rdi      # 0xafd0
leaq 0x1ceb(%rip), %rsi      # 0x836a
callq 0x32f0
movq 0x4945(%rip), %rcx      # 0xafd0
movq (%rcx), %rax
movq -0x18(%rax), %rdi
addq %rcx, %rdi
movl $0xa, %esi
callq 0x32b0
movsbl %al, %esi
movq 0x4927(%rip), %rdi      # 0xafd0
callq 0x3030
movb $0x1, %r13b
movq %rax, %rdi
callq 0x31f0
jmp 0x6925
movl (%rsp), %edx
movl 0x4(%rsp), %ecx
leaq 0xd0(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1cad(%rip), %rsi      # 0x8384
xorl %eax, %eax
callq 0x3080
leaq 0x48(%rsp), %rax
movq %rax, 0x38(%rsp)
movq %rbp, %rdi
callq 0x3140
leaq (%rsp,%rax), %rdx
addq $0xd0, %rdx
leaq 0x38(%rsp), %rdi
movq %rbp, %rsi
callq 0x5d90
movq 0x18(%rsp), %rbp
movq (%rbp), %rax
leaq 0x70(%rsp), %rcx
movq %rcx, 0x60(%rsp)
movq 0x10(%rax), %rsi
movq 0x18(%rax), %rdx
addq %rsi, %rdx
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
callq 0x6f2a
movq (%rbp), %rsi
movq %rbp, %rdi
callq 0x725c
movq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0x7288
movq 0x10(%rsp), %rdi
movq %rax, %rsi
callq 0x7330
movq 0x18(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x706c
movq %rax, %rdi
movq 0x18(%rsp), %rsi
callq 0x3050
incq 0x40(%r15)
movq 0x10(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x70ba
movq 0x60(%rsp), %rdi
leaq 0x70(%rsp), %rax
cmpq %rax, %rdi
je 0x679c
callq 0x3290
movq 0x38(%rsp), %rdi
leaq 0x48(%rsp), %rax
cmpq %rax, %rdi
je 0x67b0
callq 0x3290
leaq 0x80(%rsp), %rsi
movq %rsp, %rdx
callq 0x6bba
movsd 0x20(%rsp), %xmm0
addsd 0x1b1a(%rip), %xmm0     # 0x82e8
ucomisd 0x8(%rsp), %xmm0
jbe 0x68f4
leaq 0x80(%rsp), %rax
cmpq 0x30(%rsp), %rax
je 0x6818
movq 0x30(%rsp), %rcx
movq (%rcx), %rax
movq 0x8(%rcx), %rcx
subq %rax, %rcx
je 0x6818
sarq $0x2, %rcx
movq 0x80(%rsp), %rdx
xorl %esi, %esi
movl (%rdx,%rsi,4), %edi
movl %edi, (%rax,%rsi,4)
incq %rsi
movl %esi, %edi
cmpq %rdi, %rcx
ja 0x6808
movl $0x2, %edx
movq 0x47ac(%rip), %rdi      # 0xafd0
leaq 0x1a76(%rip), %rsi      # 0x82a1
callq 0x32f0
movq 0x4799(%rip), %rdi      # 0xafd0
movl %r12d, %esi
callq 0x3400
movq %rax, %rbp
movl $0x8, %edx
movq %rax, %rdi
leaq 0x1a53(%rip), %rsi      # 0x82a4
callq 0x32f0
movq %rbp, %rdi
movsd 0x8(%rsp), %xmm0
callq 0x3380
movq %rax, %rbp
movl $0x7, %edx
movq %rax, %rdi
leaq 0x1b13(%rip), %rsi      # 0x8389
callq 0x32f0
movl (%rsp), %esi
movq %rbp, %rdi
callq 0x3400
movq %rax, %rbp
movl $0x3, %edx
movq %rax, %rdi
leaq 0x1a20(%rip), %rsi      # 0x82b8
callq 0x32f0
movl 0x4(%rsp), %esi
movq %rbp, %rdi
callq 0x3400
movq %rax, %rbp
movl $0x10, %edx
movq %rax, %rdi
leaq 0x1ad6(%rip), %rsi      # 0x8391
callq 0x32f0
movq (%rbp), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x32b0
movsbl %al, %esi
movq %rbp, %rdi
callq 0x3030
movq %rax, %rdi
callq 0x31f0
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
callq 0x31d0
subq 0x58(%rsp), %rax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
divsd 0x1742(%rip), %xmm0     # 0x8050
ucomisd 0x10(%r15), %xmm0
jbe 0x6919
movb $0x1, %r13b
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
testb $0x1, %r13b
je 0x6503
movq 0x30(%rsp), %rax
movl %r12d, 0x48(%rax)
leaq 0xa8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x694e
callq 0x3290
movq 0x80(%rsp), %rdi
testq %rdi, %rdi
je 0x6960
callq 0x3290
movb $0x1, %al
addq $0x108, %rsp            # imm = 0x108
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rdx, %r14
movq %rax, %rbx
jmp 0x69cf
jmp 0x69bc
jmp 0x6982
jmp 0x69bc
movq %rdx, %r14
movq %rax, %rbx
jmp 0x69a4
movq %rdx, %r14
movq %rax, %rbx
movq 0x60(%rsp), %rdi
leaq 0x70(%rsp), %rax
cmpq %rax, %rdi
je 0x69a4
callq 0x3290
movq 0x38(%rsp), %rdi
leaq 0x48(%rsp), %rax
cmpq %rax, %rdi
je 0x69c2
callq 0x3290
jmp 0x69c2
jmp 0x69bc
movq %rdx, %r14
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
callq 0x6330
cmpl $0x1, %r14d
jne 0x6a2c
movq %rbx, %rdi
callq 0x3130
movq %rax, %rbx
movq 0x45e9(%rip), %rdi      # 0xafd0
leaq 0x18ce(%rip), %rsi      # 0x82bc
movl $0xe, %edx
callq 0x32f0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movq 0x45c8(%rip), %rdi      # 0xafd0
movq %rax, %rsi
callq 0x32c0
movq %rax, %rdi
callq 0x3150
callq 0x33c0
xorl %eax, %eax
jmp 0x6962
movq %rax, %rbx
callq 0x33c0
movq %rbx, %rdi
callq 0x3410
movq %rax, %rdi
callq 0x6356