// File: /workspace/github_cpp_makefile_star2_O2/lioncedric[P]cimpressGridCoverage/src/main.cc
// Function: algoTabuMPI(int*, int, int, int, int)
void algoTabuMPI(int * puzzle_step, const int height, const int width, const int nbNeigbours, const int tps) {
    const int numProc = MPI::COMM_WORLD.Get_rank();
    const int nbProc = MPI::COMM_WORLD.Get_size();
    //initialize the seed for all the process
    int seed;

    if (numProc == 0) {
        srand(time(NULL));
        seed = rand();

        for (int it = 1; it < nbProc; it++) {
            seed = rand();
            MPI::COMM_WORLD.Send(&seed, 1, MPI::INT, it, 10);
        }

    } else {
        MPI::COMM_WORLD.Recv(&seed, 1, MPI::INT, 0, 10);
        srand(seed);
    }

    //timer
    double start = MPI::Wtime();
    double end;

    //the number of increments
    int count = 0;

    //first solution is calculated on the full area starting form the top left corner
    int area[4] = {1, 1, width - 2, height - 2};
    int f_step = solver(puzzle_step, width, 1, area);
    if (numProc == 0) {
        cout << "init : " << f_step << endl;
    }
    //fmin is now the first solution
    int fmin = f_step;
    int fminpuzzle[height * width];
    memcpy(fminpuzzle, puzzle_step, height * width * sizeof *puzzle_step);

    //iterations variables

    int f;
    int test;
    int params[4];
    int fparams[4];
    int squares_removed[height * width * 3]; //for better performance array size is initialized to maximum (instead of a list)

    //taboo list
    list< int > listeS1;

    //start
    do {
        //neighbour solution min 
        f = 9999999;

        for (int nb = 0; nb < nbNeigbours / nbProc; ++nb) {
            //Calculation of the next neighbour
            params[0] = 1 + rand() % (width - 2); //x0
            params[1] = 1 + rand() % (height - 2); //y0 
            params[2] = 1 + rand() % 20; //size
            params[3] = rand() % 4; //solver orientation

            //define the area to recompute
            area[0] = params[0];
            area[1] = params[1];
            area[2] = min(params[0] + params[2], width - 2);
            area[3] = min(params[1] + params[2], height - 2);

            //clear area with 1 and recalulate the area accorting to the squares removed
            int nb_squares_removed = clear_squares(puzzle_step, width, area, squares_removed);
            //compute area previously removed
            int nb_squares_used = solver(puzzle_step, width, params[3], area);
            //get result
            test = f_step - nb_squares_removed + nb_squares_used;

            //save if best neighbour
            if (find(listeS1.begin(), listeS1.end(), test) == listeS1.end()) {
                if (test < f) {
                    fparams[0] = params[0];
                    fparams[1] = params[1];

                    fparams[2] = params[2];
                    fparams[3] = params[3];
                    f = test;
                }
            }
            //back to original to process new neighbour
            use_squares(puzzle_step, width, squares_removed);
        }
        //get best neighbour from all proc
        if (numProc == 0) {
            for (int it = 1; it < nbProc; it++) {
                MPI::COMM_WORLD.Recv(&test, 1, MPI::INT, it, 1);
                MPI::COMM_WORLD.Recv(params, 4, MPI::INT, it, 4);

                if (test < f) {
                    fparams[0] = params[0];
                    fparams[1] = params[1];

                    fparams[2] = params[2];
                    fparams[3] = params[3];
                    f = test;
                }
            }

        } else {
            MPI::COMM_WORLD.Send(&f, 1, MPI::INT, 0, 1);
            MPI::COMM_WORLD.Send(fparams, 4, MPI::INT, 0, 4);
        }
        MPI::COMM_WORLD.Bcast(fparams, 4, MPI::INT, 0);
        MPI::COMM_WORLD.Bcast(&f, 1, MPI::INT, 0);

        //if a neighbour was saved use it for the next iterations
        if (f < 9999999) {
            area[0] = fparams[0];
            area[1] = fparams[1];
            area[2] = min(fparams[0] + fparams[2], width - 2);
            area[3] = min(fparams[1] + fparams[2], height - 2);
            clear_squares(puzzle_step, width, area, squares_removed);
            solver(puzzle_step, width, fparams[3], area);
            f_step = f;
        }
        //update tabu list
        if (listeS1.size() > 3) {
            listeS1.pop_back();
        }
        listeS1.push_front(f);

        if (numProc == 0 && f < fmin) {
            fmin = f_step;
            memcpy(fminpuzzle, puzzle_step, height * width * sizeof *puzzle_step);
            cout << fmin << endl;
        }
        count++;

        //there is no way to know is the best anwser is found so we stop after a certain duration
        end = MPI::Wtime() - start;
        MPI::COMM_WORLD.Bcast(&end, 1, MPI::DOUBLE, 0);


    } while (end < tps);
    if (numProc == 0) {
        memcpy(puzzle_step, fminpuzzle, height * width * sizeof *fminpuzzle);
        cout << "Computation Performances : " << count * nbNeigbours << endl;
    }

}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movl %r8d, -0x30(%rbp)
movl %ecx, -0x6c(%rbp)
movq %rdx, -0x98(%rbp)
movq %rsi, -0x68(%rbp)
movq %rdi, -0x40(%rbp)
movq 0x3b43(%rip), %rbx      # 0x5fc0
movq %rbx, %rdi
callq 0x2d32
movl %eax, %r12d
movq %rbx, %rdi
callq 0x2d50
movl %eax, -0x44(%rbp)
movl %r12d, -0x34(%rbp)
testl %r12d, %r12d
je 0x29ad
movq 0x3b19(%rip), %rdi      # 0x5fc0
movq 0x3b1a(%rip), %rcx      # 0x5fc8
leaq -0x80(%rbp), %rbx
pushq $0x1
popq %rdx
pushq $0xa
popq %r9
movq %rbx, %rsi
xorl %r8d, %r8d
callq 0x2d6e
movl (%rbx), %edi
callq 0x2180
callq 0x21d0
movsd %xmm0, -0xe8(%rbp)
movabsq $0x100000001, %rax      # imm = 0x100000001
leaq -0x60(%rbp), %rcx
movq %rax, (%rcx)
movq -0x98(%rbp), %rbx
leal -0x2(%rbx), %eax
movl %eax, -0x7c(%rbp)
movl %eax, 0x8(%rcx)
movq -0x68(%rbp), %r13
leal -0x2(%r13), %eax
movl %eax, -0x78(%rbp)
movl %eax, 0xc(%rcx)
pushq $0x1
popq %rdx
movq -0x40(%rbp), %r14
movq %r14, %rdi
movl %ebx, %esi
callq 0x3584
movl %eax, %r12d
cmpl $0x0, -0x34(%rbp)
jne 0x2547
movq 0x3aa8(%rip), %rdi      # 0x5fd0
leaq 0x1ad5(%rip), %rsi      # 0x4004
callq 0x2190
movq %rax, %rdi
movl %r12d, %esi
callq 0x2290
movq %rax, %rdi
callq 0x20e0
movq %rsp, -0xd8(%rbp)
imull %ebx, %r13d
leaq 0xf(,%r13,4), %rax
andq $-0x10, %rax
movq %rsp, %rdi
subq %rax, %rdi
movq %rdi, %rsp
movslq %r13d, %rbx
leaq (,%rbx,4), %rdx
movq %rdi, -0xc8(%rbp)
movq %r14, %rsi
movq %rdx, -0xc0(%rbp)
callq 0x2140
leal (%rbx,%rbx,2), %eax
leaq 0xf(,%rax,4), %rax
andq $-0x10, %rax
movq %rsp, %rcx
subq %rax, %rcx
movq %rcx, -0x68(%rbp)
movq %rcx, %rsp
leaq -0x100(%rbp), %r13
movq %r13, 0x8(%r13)
movq %r13, (%r13)
andq $0x0, 0x10(%r13)
movl -0x6c(%rbp), %eax
cltd
idivl -0x44(%rbp)
cvtsi2sdl -0x30(%rbp), %xmm0
movsd %xmm0, -0xe0(%rbp)
xorl %ecx, %ecx
testl %eax, %eax
movl $0x0, -0x70(%rbp)
cmovlel %ecx, %eax
movl %eax, -0xb4(%rbp)
movq 0x39d9(%rip), %rdi      # 0x5fc0
movl %r12d, -0x74(%rbp)
movl %r12d, -0x30(%rbp)
movl $0x98967f, -0x2c(%rbp)  # imm = 0x98967F
movl -0xb4(%rbp), %r14d
movq 0x39c4(%rip), %r12      # 0x5fc8
subl $0x1, %r14d
jb 0x2726
callq 0x2080
cltd
movl -0x7c(%rbp), %ebx
idivl %ebx
incl %edx
movl %edx, -0x90(%rbp)
callq 0x2080
cltd
movl -0x78(%rbp), %r15d
idivl %r15d
incl %edx
movl %edx, -0x8c(%rbp)
callq 0x2080
cltd
pushq $0x14
popq %rcx
idivl %ecx
incl %edx
movl %edx, -0x88(%rbp)
callq 0x2080
cltd
pushq $0x4
popq %rcx
idivl %ecx
movl %edx, -0x84(%rbp)
movl -0x90(%rbp), %eax
movl -0x8c(%rbp), %ecx
movl %eax, -0x60(%rbp)
movl %ecx, -0x5c(%rbp)
movl -0x88(%rbp), %edx
addl %edx, %eax
cmpl %eax, %ebx
cmovll %ebx, %eax
movl %eax, -0x58(%rbp)
addl %ecx, %edx
cmpl %edx, %r15d
cmovll %r15d, %edx
movl %edx, -0x54(%rbp)
movq -0x40(%rbp), %r13
movq %r13, %rdi
movq -0x98(%rbp), %r15
movl %r15d, %esi
leaq -0x60(%rbp), %r12
movq %r12, %rdx
movq -0x68(%rbp), %rcx
callq 0x3316
movl %eax, %ebx
movl -0x84(%rbp), %edx
movq %r13, %rdi
movl %r15d, %esi
movq %r12, %rcx
callq 0x3584
leaq -0x100(%rbp), %r13
movq 0x38fb(%rip), %r12      # 0x5fc8
movl -0x30(%rbp), %ecx
subl %ebx, %ecx
addl %eax, %ecx
movl %ecx, -0x38(%rbp)
movq -0x100(%rbp), %rdi
movq %r13, %rsi
leaq -0x38(%rbp), %rdx
callq 0x2e38
cmpq %r13, %rax
jne 0x270a
movl -0x38(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x270a
movapd -0x90(%rbp), %xmm0
movapd %xmm0, -0xb0(%rbp)
movl %eax, -0x2c(%rbp)
movq -0x40(%rbp), %rdi
movl %r15d, %esi
movq -0x68(%rbp), %rdx
callq 0x352a
movq 0x389f(%rip), %rdi      # 0x5fc0
jmp 0x2604
cmpl $0x0, -0x34(%rbp)
je 0x28d4
leaq -0x2c(%rbp), %rsi
pushq $0x1
popq %rbx
movl %ebx, %edx
movq %r12, %rcx
xorl %r8d, %r8d
movl %ebx, %r9d
callq 0x2d14
movl %ebx, %r12d
movq 0x386f(%rip), %rdi      # 0x5fc0
leaq -0xb0(%rbp), %rsi
pushq $0x4
popq %rdx
movq 0x3866(%rip), %rcx      # 0x5fc8
xorl %r8d, %r8d
movl %edx, %r9d
callq 0x2d14
movq 0x384c(%rip), %rdi      # 0x5fc0
leaq -0xb0(%rbp), %rsi
pushq $0x4
popq %rdx
movq 0x3843(%rip), %rcx      # 0x5fc8
xorl %r8d, %r8d
callq 0x2d94
movq 0x382c(%rip), %rdi      # 0x5fc0
leaq -0x2c(%rbp), %rsi
movl %r12d, %edx
movq 0x3826(%rip), %rcx      # 0x5fc8
xorl %r8d, %r8d
callq 0x2d94
cmpl $0x98967e, -0x2c(%rbp)  # imm = 0x98967E
jg 0x281d
movl -0xb0(%rbp), %eax
movl -0xac(%rbp), %ecx
movl %eax, -0x60(%rbp)
movl %ecx, -0x5c(%rbp)
movl -0xa8(%rbp), %edx
addl %edx, %eax
movl -0x7c(%rbp), %esi
cmpl %eax, %esi
cmovll %esi, %eax
movl %eax, -0x58(%rbp)
addl %ecx, %edx
movl -0x78(%rbp), %eax
cmpl %edx, %eax
cmovll %eax, %edx
movl %edx, -0x54(%rbp)
movq -0x40(%rbp), %rdi
movq -0x98(%rbp), %rsi
leaq -0x60(%rbp), %rdx
movq -0x68(%rbp), %rcx
callq 0x3316
movl -0xa4(%rbp), %edx
movq -0x40(%rbp), %rdi
movq -0x98(%rbp), %rsi
leaq -0x60(%rbp), %rcx
callq 0x3584
movl -0x2c(%rbp), %eax
movl %eax, -0x30(%rbp)
cmpq $0x4, -0xf0(%rbp)
jb 0x282f
movq %r13, %rdi
callq 0x2db0
movq %r13, %rdi
leaq -0x2c(%rbp), %rsi
callq 0x2dba
cmpl $0x0, -0x34(%rbp)
jne 0x287d
movl -0x74(%rbp), %eax
cmpl %eax, -0x2c(%rbp)
jge 0x287d
movq -0xc8(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq -0xc0(%rbp), %rdx
callq 0x2140
movq 0x3769(%rip), %rdi      # 0x5fd0
movl -0x30(%rbp), %esi
callq 0x2290
movq %rax, %rdi
callq 0x20e0
movl -0x30(%rbp), %eax
movl %eax, -0x74(%rbp)
callq 0x21d0
subsd -0xe8(%rbp), %xmm0
movsd %xmm0, -0xd0(%rbp)
movq 0x3727(%rip), %rdi      # 0x5fc0
leaq -0xd0(%rbp), %rsi
movl %r12d, %edx
movq 0x372e(%rip), %rcx      # 0x5fd8
xorl %r8d, %r8d
callq 0x2d94
incl -0x70(%rbp)
movsd -0xe0(%rbp), %xmm0
ucomisd -0xd0(%rbp), %xmm0
movq 0x36f4(%rip), %rdi      # 0x5fc0
ja 0x25ef
jmp 0x2944
pushq $0x1
popq %r12
movl %r12d, %ebx
cmpl -0x44(%rbp), %ebx
jge 0x276d
movq 0x36d5(%rip), %r15      # 0x5fc0
movq %r15, %rdi
leaq -0x38(%rbp), %rsi
movl %r12d, %edx
movq 0x36cc(%rip), %r14      # 0x5fc8
movq %r14, %rcx
movl %ebx, %r8d
movl %r12d, %r9d
callq 0x2d6e
movq %r15, %rdi
leaq -0x90(%rbp), %rsi
pushq $0x4
popq %rdx
movq %r14, %rcx
movl %ebx, %r8d
movl %edx, %r9d
callq 0x2d6e
movl -0x38(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x2940
movapd -0x90(%rbp), %xmm0
movapd %xmm0, -0xb0(%rbp)
movl %eax, -0x2c(%rbp)
incl %ebx
jmp 0x28db
cmpl $0x0, -0x34(%rbp)
jne 0x298b
movq -0x40(%rbp), %rdi
movq -0xc8(%rbp), %rsi
movq -0xc0(%rbp), %rdx
callq 0x2140
movq 0x3668(%rip), %rdi      # 0x5fd0
leaq 0x169d(%rip), %rsi      # 0x400c
callq 0x2190
movl -0x70(%rbp), %esi
imull -0x6c(%rbp), %esi
movq %rax, %rdi
callq 0x2290
movq %rax, %rdi
callq 0x20e0
leaq -0x100(%rbp), %rdi
callq 0x2e0e
movq -0xd8(%rbp), %rsp
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x1
popq %r12
xorl %edi, %edi
callq 0x2170
movl %eax, %edi
callq 0x2180
callq 0x2080
leaq -0x80(%rbp), %rcx
movq %rcx, %r14
movl %eax, (%rcx)
movq 0x35f4(%rip), %r13      # 0x5fc8
pushq $0xa
popq %rbx
movl %r12d, %r15d
cmpl -0x44(%rbp), %r12d
jge 0x24cb
callq 0x2080
movl %eax, -0x80(%rbp)
movq 0x35cd(%rip), %rdi      # 0x5fc0
movq %r14, %rsi
movl %r15d, %edx
movq %r13, %rcx
movl %r12d, %r8d
movl %ebx, %r9d
callq 0x2d14
incl %r12d
jmp 0x29da
jmp 0x2a16
jmp 0x2a16
jmp 0x2a16
jmp 0x2a16
jmp 0x2a16
movq %rax, %rbx
leaq -0x100(%rbp), %rdi
callq 0x2e0e
movq %rbx, %rdi
callq 0x22a0