// File: /workspace/github_cpp_makefile_star2_O3/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, -0xc8(%rbp)
movq %rsi, -0x68(%rbp)
movq %rdi, -0x48(%rbp)
movq 0x4b6b(%rip), %r14      # 0x6fb8
movq 0x8(%r14), %rdi
leaq -0xa8(%rbp), %rbx
movq %rbx, %rsi
callq 0x21f0
movl (%rbx), %ebx
movq 0x8(%r14), %rdi
leaq -0xa8(%rbp), %r12
movq %r12, %rsi
callq 0x21c0
movl (%r12), %r15d
movl %ebx, -0x38(%rbp)
testl %ebx, %ebx
je 0x24bb
movq 0x4b41(%rip), %rax      # 0x6fc8
movq 0x8(%rax), %rdx
movq 0x8(%r14), %r9
subq $0x8, %rsp
leaq -0x40(%rbp), %rbx
movq %rbx, %rdi
movl $0x1, %esi
xorl %ecx, %ecx
movl $0xa, %r8d
pushq $0x0
callq 0x2120
addq $0x10, %rsp
movl (%rbx), %edi
callq 0x2160
jmp 0x2516
xorl %edi, %edi
callq 0x2150
movl %eax, %edi
callq 0x2160
callq 0x2070
movl %eax, -0x40(%rbp)
cmpl $0x2, %r15d
jl 0x2516
movl $0x1, %r13d
leaq -0x40(%rbp), %rbx
callq 0x2070
movl %eax, -0x40(%rbp)
movq 0x4ad8(%rip), %rax      # 0x6fc8
movq 0x8(%rax), %rdx
movq 0x8(%r14), %r9
movq %rbx, %rdi
movl $0x1, %esi
movl %r13d, %ecx
movl $0xa, %r8d
callq 0x20b0
incl %r13d
cmpl %r13d, %r15d
jne 0x24e1
movl %r15d, -0x3c(%rbp)
callq 0x21d0
movsd %xmm0, -0xf8(%rbp)
movabsq $0x100000001, %rax      # imm = 0x100000001
leaq -0x60(%rbp), %rcx
movq %rax, (%rcx)
movq -0xc8(%rbp), %rbx
leal -0x2(%rbx), %eax
movl %eax, -0x74(%rbp)
movl %eax, 0x8(%rcx)
movq -0x68(%rbp), %r14
leal -0x2(%r14), %eax
movl %eax, -0x70(%rbp)
movl %eax, 0xc(%rcx)
movq -0x48(%rbp), %r13
movq %r13, %rdi
movl %ebx, %esi
movl $0x1, %edx
callq 0x4126
movl %eax, %r15d
cmpl $0x0, -0x38(%rbp)
movl %eax, -0x34(%rbp)
jne 0x25cf
movq %r13, %r15
movq 0x4a51(%rip), %r13      # 0x6fd0
leaq 0x2a7e(%rip), %rsi      # 0x5004
movl $0x7, %edx
movq %r13, %rdi
callq 0x21b0
movq %r13, %rdi
movl -0x34(%rbp), %esi
callq 0x2280
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2170
movsbl %al, %esi
movq %r13, %rdi
movq %r15, %r13
movl -0x34(%rbp), %r15d
callq 0x2030
movq %rax, %rdi
callq 0x20f0
movq %rsp, -0xe8(%rbp)
imull %ebx, %r14d
leaq 0xf(,%r14,4), %rax
andq $-0x10, %rax
movq %rsp, %rdi
subq %rax, %rdi
movq %rdi, %rsp
movslq %r14d, %r14
leaq (,%r14,4), %rdx
movq %rdi, -0xd8(%rbp)
movq %r13, %rsi
movq %rdx, -0xd0(%rbp)
callq 0x2130
leal (%r14,%r14,2), %eax
leaq 0xf(,%rax,4), %rax
andq $-0x10, %rax
movq %rsp, %rcx
subq %rax, %rcx
movq %rcx, -0x68(%rbp)
movq %rcx, %rsp
movq %r12, -0xa0(%rbp)
movq %r12, -0xa8(%rbp)
movq $0x0, -0x98(%rbp)
movl -0x6c(%rbp), %eax
cltd
idivl -0x3c(%rbp)
movl %eax, -0x78(%rbp)
xorps %xmm0, %xmm0
cvtsi2sdl -0x30(%rbp), %xmm0
movsd %xmm0, -0xf0(%rbp)
xorl %r14d, %r14d
movq 0x495e(%rip), %r12      # 0x6fc8
movl %r15d, -0x30(%rbp)
movl %r14d, -0xc8(%rbp)
movl $0x98967f, -0x2c(%rbp)  # imm = 0x98967F
cmpl $0x0, -0x78(%rbp)
jle 0x27d5
xorl %r14d, %r14d
callq 0x2070
cltd
movl -0x74(%rbp), %r15d
idivl %r15d
incl %edx
movl %edx, -0x90(%rbp)
callq 0x2070
cltd
movl -0x70(%rbp), %r13d
idivl %r13d
incl %edx
movl %edx, -0x8c(%rbp)
callq 0x2070
cltq
imulq $0x66666667, %rax, %rcx # imm = 0x66666667
movq %rcx, %rdx
shrq $0x3f, %rdx
sarq $0x23, %rcx
addl %edx, %ecx
shll $0x2, %ecx
leal (%rcx,%rcx,4), %ecx
negl %ecx
addl %ecx, %eax
incl %eax
movl %eax, -0x88(%rbp)
callq 0x2070
leal 0x3(%rax), %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
andl $-0x4, %ecx
subl %ecx, %eax
movl %eax, -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, %r15d
cmovll %r15d, %eax
movl %eax, -0x58(%rbp)
addl %ecx, %edx
cmpl %edx, %r13d
cmovll %r13d, %edx
movl %edx, -0x54(%rbp)
movq %rbx, %r15
movq -0x48(%rbp), %rbx
movq %rbx, %rdi
movl %r15d, %esi
leaq -0x60(%rbp), %r12
movq %r12, %rdx
movq -0x68(%rbp), %rcx
callq 0x39be
movl %eax, %r13d
movl -0x84(%rbp), %edx
movq %rbx, %rdi
movl %r15d, %esi
movq %r12, %rcx
callq 0x4126
leaq -0xa8(%rbp), %rsi
movq 0x485e(%rip), %r12      # 0x6fc8
movq %r15, %rbx
movl -0x30(%rbp), %ecx
subl %r13d, %ecx
addl %ecx, %eax
movl %eax, -0x7c(%rbp)
movq -0xa8(%rbp), %rcx
movq %rsi, %rdx
cmpq %rsi, %rcx
je 0x279c
cmpl %eax, 0x10(%rcx)
je 0x2799
movq (%rcx), %rcx
cmpq %rsi, %rcx
jne 0x2787
movq %rsi, %rdx
jmp 0x279c
movq %rcx, %rdx
cmpq %rsi, %rdx
jne 0x27b9
cmpl -0x2c(%rbp), %eax
jge 0x27b9
movapd -0x90(%rbp), %xmm0
movapd %xmm0, -0xc0(%rbp)
movl %eax, -0x2c(%rbp)
movq -0x48(%rbp), %rdi
movl %ebx, %esi
movq -0x68(%rbp), %rdx
callq 0x3f06
incl %r14d
cmpl -0x78(%rbp), %r14d
jne 0x2689
cmpl $0x0, -0x38(%rbp)
je 0x2833
movq 0x8(%r12), %rdx
movq 0x47d1(%rip), %rax      # 0x6fb8
movq 0x8(%rax), %r9
leaq -0x2c(%rbp), %rdi
movl $0x1, %esi
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x20b0
movq -0x48(%rbp), %r14
movq 0x8(%r12), %rdx
movq 0x47a7(%rip), %rax      # 0x6fb8
movq 0x8(%rax), %r9
leaq -0xc0(%rbp), %rdi
movl $0x4, %esi
xorl %ecx, %ecx
movl $0x4, %r8d
callq 0x20b0
jmp 0x28cd
cmpl $0x2, -0x3c(%rbp)
movq -0x48(%rbp), %r14
jl 0x28cd
movl $0x1, %r13d
movq 0x8(%r12), %rdx
movq 0x4765(%rip), %r15      # 0x6fb8
movq 0x8(%r15), %r9
subq $0x8, %rsp
leaq -0x7c(%rbp), %rdi
movl $0x1, %esi
movl %r13d, %ecx
movl $0x1, %r8d
pushq $0x0
callq 0x2120
addq $0x10, %rsp
movq 0x8(%r12), %rdx
movq 0x8(%r15), %r9
subq $0x8, %rsp
leaq -0x90(%rbp), %rdi
movl $0x4, %esi
movl %r13d, %ecx
movl $0x4, %r8d
pushq $0x0
callq 0x2120
addq $0x10, %rsp
movl -0x7c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x28c0
movapd -0x90(%rbp), %xmm0
movapd %xmm0, -0xc0(%rbp)
movl %eax, -0x2c(%rbp)
incl %r13d
cmpl %r13d, -0x3c(%rbp)
jne 0x2847
movq 0x8(%r12), %rdx
movq 0x46df(%rip), %rax      # 0x6fb8
movq 0x8(%rax), %r8
leaq -0xc0(%rbp), %rdi
movl $0x4, %esi
xorl %ecx, %ecx
callq 0x2050
movq 0x8(%r12), %rdx
movq 0x46bc(%rip), %rax      # 0x6fb8
movq 0x8(%rax), %r8
leaq -0x2c(%rbp), %rdi
movl $0x1, %esi
xorl %ecx, %ecx
callq 0x2050
cmpl $0x98967e, -0x2c(%rbp)  # imm = 0x98967E
jg 0x2977
movl -0xc0(%rbp), %eax
movl -0xbc(%rbp), %ecx
movl %eax, -0x60(%rbp)
movl %ecx, -0x5c(%rbp)
movl -0xb8(%rbp), %edx
addl %edx, %eax
movl -0x74(%rbp), %esi
cmpl %eax, %esi
cmovll %esi, %eax
movl %eax, -0x58(%rbp)
addl %ecx, %edx
movl -0x70(%rbp), %eax
cmpl %edx, %eax
cmovll %eax, %edx
movl %edx, -0x54(%rbp)
movq %r14, %rdi
movl %ebx, %esi
leaq -0x60(%rbp), %rdx
movq -0x68(%rbp), %rcx
callq 0x39be
movl -0xb4(%rbp), %edx
movq %r14, %rdi
movl %ebx, %esi
leaq -0x60(%rbp), %rcx
callq 0x4126
movl -0x2c(%rbp), %eax
movl %eax, -0x30(%rbp)
movq -0x98(%rbp), %rax
cmpq $0x4, %rax
jb 0x29aa
movq -0xa0(%rbp), %r13
decq %rax
movq %rax, -0x98(%rbp)
movq %r13, %rdi
callq 0x2260
movl $0x18, %esi
movq %r13, %rdi
callq 0x2190
movq -0xa8(%rbp), %r13
movl $0x18, %edi
callq 0x2180
movl -0x2c(%rbp), %ecx
movl %ecx, 0x10(%rax)
movq %rax, %rdi
movq %r13, %rsi
callq 0x2040
incq -0x98(%rbp)
cmpl $0x0, -0x38(%rbp)
jne 0x2a36
movl -0x34(%rbp), %eax
cmpl %eax, -0x2c(%rbp)
jge 0x2a36
movq -0xd8(%rbp), %rdi
movq %r14, %rsi
movq -0xd0(%rbp), %rdx
callq 0x2130
movq 0x45d2(%rip), %rdi      # 0x6fd0
movl -0x30(%rbp), %esi
callq 0x2280
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2170
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20f0
movl -0x30(%rbp), %eax
movl %eax, -0x34(%rbp)
callq 0x21d0
subsd -0xf8(%rbp), %xmm0
movsd %xmm0, -0xe0(%rbp)
movq 0x4586(%rip), %rax      # 0x6fd8
movq 0x8(%rax), %rdx
movq 0x455b(%rip), %rax      # 0x6fb8
movq 0x8(%rax), %r8
leaq -0xe0(%rbp), %rdi
movl $0x1, %esi
xorl %ecx, %ecx
callq 0x2050
movl -0xc8(%rbp), %r14d
incl %r14d
movsd -0xf0(%rbp), %xmm0
ucomisd -0xe0(%rbp), %xmm0
ja 0x266e
cmpl $0x0, -0x38(%rbp)
jne 0x2b07
movq -0x48(%rbp), %rdi
movq -0xd8(%rbp), %rsi
movq -0xd0(%rbp), %rdx
callq 0x2130
movq 0x4518(%rip), %rdi      # 0x6fd0
leaq 0x254d(%rip), %rsi      # 0x500c
movl $0x1b, %edx
callq 0x21b0
imull -0x6c(%rbp), %r14d
movq 0x44fb(%rip), %rdi      # 0x6fd0
movl %r14d, %esi
callq 0x2280
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2170
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20f0
leaq -0xa8(%rbp), %rbx
movq (%rbx), %rdi
cmpq %rbx, %rdi
je 0x2b2b
movq (%rdi), %r14
movl $0x18, %esi
callq 0x2190
movq %r14, %rdi
cmpq %rbx, %r14
jne 0x2b16
movq -0xe8(%rbp), %rsp
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2b49
jmp 0x2b49
jmp 0x2b49
jmp 0x2b49
movq %rax, %rbx
leaq -0xa8(%rbp), %r14
movq (%r14), %rdi
cmpq %r14, %rdi
je 0x2b70
movq (%rdi), %r15
movl $0x18, %esi
callq 0x2190
movq %r15, %rdi
cmpq %r14, %r15
jne 0x2b5b
movq %rbx, %rdi
callq 0x2290