// File: /workspace/github_cpp_makefile_star2_O2/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, 0x28(%rsp)
movq %rdx, %rbx
movq %rsi, %r14
movq %rdi, %r15
addq $0x48, %rdi
movq %rdi, 0x18(%rsp)
callq 0x5f24
leaq 0x30(%r15), %rdi
movq %rdi, 0x38(%rsp)
callq 0x5ef8
leaq 0x80(%rsp), %rdi
movq %rbx, %rsi
callq 0x5562
leaq 0x80(%rsp), %rdi
movq %r14, %rsi
callq 0x476c
movsd %xmm0, 0x8(%rsp)
xorl %ebp, %ebp
callq 0x31a0
movq %rax, 0x30(%rsp)
movq 0x5850(%rip), %rbx      # 0xafd0
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
xorl %r13d, %r13d
testb $0x1, %bpl
jne 0x5a62
leal 0x1(%r13), %r12d
cmpl $0x13, (%r14)
jg 0x5816
leaq 0x80(%rsp), %rdi
movq %rbx, %rsi
callq 0x4f56
movq %rbx, %rdi
leaq 0x1a9a(%rip), %rsi      # 0x7257
callq 0x3250
movq %rax, %rdi
movl %r12d, %esi
callq 0x33a0
movq %rax, %rdi
leaq 0x1a83(%rip), %rsi      # 0x725a
callq 0x3250
movq %rax, %rdi
movsd 0x8(%rsp), %xmm0
callq 0x3320
movq %rax, %rdi
leaq 0x1b33(%rip), %rsi      # 0x7327
callq 0x3250
movq %rax, %rdi
movsd 0x20(%rsp), %xmm0
callq 0x3320
movq %rax, %rdi
leaq 0x1a52(%rip), %rsi      # 0x7263
callq 0x3250
movq %r15, %rdi
movq %r14, %rsi
leaq 0x80(%rsp), %rdx
leaq 0x10(%rsp), %rcx
callq 0x5b3c
addsd 0x8(%rsp), %xmm0
ucomisd 0x20(%r14), %xmm0
jb 0x585e
movq %rbx, %rdi
leaq 0x1ae4(%rip), %rsi      # 0x732a
callq 0x3250
movb $0x1, %bpl
movq %rax, %rdi
callq 0x3130
movl %r12d, %r13d
jmp 0x578f
movsd %xmm0, 0x8(%rsp)
movl 0x8(%r15), %eax
testq %rax, %rax
movq 0x38(%rsp), %r12
je 0x595b
cmpq %rax, 0x70(%r15)
jae 0x58d1
movl 0x10(%rsp), %edx
movl 0x14(%rsp), %ecx
leaq 0xd0(%rsp), %rdi
leaq 0x1ab1(%rip), %rsi      # 0x7344
xorl %eax, %eax
callq 0x3070
leaq 0x40(%rsp), %rbp
movq %rbp, %rdi
leaq 0xd0(%rsp), %rsi
leaq 0x60(%rsp), %rdx
callq 0x30f0
movq %r12, %rdi
movq %rbp, %rsi
callq 0x5f10
movq 0x18(%rsp), %rdi
movq %rbp, %rsi
callq 0x60a4
jmp 0x5953
movl 0x10(%rsp), %edx
movl 0x14(%rsp), %ecx
leaq 0xd0(%rsp), %rbp
movq %rbp, %rdi
leaq 0x1a59(%rip), %rsi      # 0x7344
xorl %eax, %eax
callq 0x3070
leaq 0x40(%rsp), %rdi
movq %rbp, %rsi
leaq 0x60(%rsp), %rbp
movq %rbp, %rdx
callq 0x30f0
movq (%r12), %rsi
addq $0x10, %rsi
movq %rbp, %rdi
callq 0x32b0
movq %r12, %rdi
callq 0x5f1c
movq 0x18(%rsp), %rdi
movq %rbp, %rsi
callq 0x62b6
leaq 0x40(%rsp), %rbp
movq %r12, %rdi
movq %rbp, %rsi
callq 0x5f10
movq 0x18(%rsp), %rdi
movq %rbp, %rsi
callq 0x60a4
leaq 0x60(%rsp), %rdi
callq 0x3120
movq %rbp, %rdi
callq 0x3120
leaq 0x80(%rsp), %rsi
leaq 0x10(%rsp), %rdx
callq 0x5c76
incl %r13d
leaq 0x80(%rsp), %rdi
movq %rdi, %rsi
callq 0x5610
movsd 0x20(%rsp), %xmm0
addsd 0x1912(%rip), %xmm0     # 0x72a0
ucomisd 0x8(%rsp), %xmm0
jbe 0x5a3c
movq 0x28(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x5610
movq %rbx, %rdi
leaq 0x18a1(%rip), %rsi      # 0x7257
callq 0x3250
movq %rax, %rdi
movl %r13d, %esi
callq 0x33a0
movq %rax, %rdi
leaq 0x188a(%rip), %rsi      # 0x725a
callq 0x3250
movq %rax, %rdi
movsd 0x8(%rsp), %xmm0
callq 0x3320
movq %rax, %rdi
leaq 0x195c(%rip), %rsi      # 0x7349
callq 0x3250
movl 0x10(%rsp), %esi
movq %rax, %rdi
callq 0x33a0
movq %rax, %rdi
leaq 0x1866(%rip), %rsi      # 0x726e
callq 0x3250
movl 0x14(%rsp), %esi
movq %rax, %rdi
callq 0x33a0
movq %rax, %rdi
leaq 0x192e(%rip), %rsi      # 0x7351
callq 0x3250
movq %rax, %rdi
callq 0x3130
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
callq 0x31a0
subq 0x30(%rsp), %rax
cvtsi2sd %rax, %xmm0
divsd 0x15dd(%rip), %xmm0     # 0x7030
ucomisd 0x10(%r15), %xmm0
seta %bpl
jmp 0x578f
movq 0x28(%rsp), %rax
movl %r13d, 0x48(%rax)
leaq 0x80(%rsp), %rdi
callq 0x5640
movb $0x1, %al
addq $0x108, %rsp            # imm = 0x108
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x5ac2
jmp 0x5a92
jmp 0x5ac2
movq %rdx, %r14
movq %rax, %rbx
jmp 0x5aaa
movq %rdx, %r14
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x3120
leaq 0x40(%rsp), %rdi
callq 0x3120
jmp 0x5ac8
movq %rdx, %r14
movq %rax, %rbx
jmp 0x5ad5
jmp 0x5ac2
jmp 0x5ac2
movq %rdx, %r14
movq %rax, %rbx
leaq 0x80(%rsp), %rdi
callq 0x5640
cmpl $0x1, %r14d
jne 0x5b2c
movq %rbx, %rdi
callq 0x3100
movq %rax, %rbx
movq 0x54e3(%rip), %rdi      # 0xafd0
leaq 0x177e(%rip), %rsi      # 0x7272
callq 0x3250
movq %rax, %r14
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movq %r14, %rdi
movq %rax, %rsi
callq 0x3250
movq %rax, %rdi
callq 0x3130
callq 0x3360
xorl %eax, %eax
jmp 0x5a7a
movq %rax, %rbx
callq 0x3360
movq %rbx, %rdi
callq 0x33b0
movq %rax, %rdi
callq 0x4a0a