// File: /workspace/github_cpp_makefile_star2_O2/xbai0624[P]dnn/./include/Layer.h
// Function: Filter2D::GenerateCompleteDropOutSet(unsigned long, double)
std::vector<Filter2D> GenerateCompleteDropOutSet(size_t nBatches, double dropoutRatio)
    {
        // generate a complete set of drop out filters
        // In this set, each element get acitvated at least once, this is to make sure during drop-out every neuron get trained
        // Parameters:
        //     nBatches: number of drop-out branches
        //     dropoutRatio: ratio of elements to drop out
        // 1) basic check
        auto dim = Dimension();

        assert(nBatches >= 1);
        assert(dropoutRatio < 1.0); // one cannot drop all of them
        int total_elements = (int)dim.first * (int)dim.second;
        // make sure there's enough positions to accomodate all elements
        assert(total_elements * (1.0-dropoutRatio) * (int)nBatches >= total_elements);

        // 2) setup a random engine
        std::random_device rd;
        std::mt19937 gen(rd());
        //std::uniform_int_distribution<> row(0, (int)dim.first-1);
        //std::uniform_int_distribution<> col(0, (int)dim.second-1);

        // 3) the result to be returned
        std::vector<Filter2D> Ret;
        for(size_t n=0;n<nBatches;n++)
        {
            Ret.push_back(Filter2D(dim.first, dim.second, false));
        }

        // 4) first save all coords
        std::vector<std::pair<int, int>> all_coords;
        for(size_t i=0;i<dim.first;i++)
        {
            for(size_t j=0;j<dim.second;j++)
                all_coords.push_back(std::pair<int, int>((int)i, (int)j));
        }

        // 5) integer part
        int average = total_elements / (int)nBatches;
        for(auto &M: Ret)
        {
            // for each Filter, set 'average' elements to true
            int True_elements = 0;
            while(True_elements<average && all_coords.size() > 0)
            {
                std::uniform_int_distribution<int> index(0, (int)all_coords.size()-1);
                int pos = index(gen);
                M[all_coords[pos].first][all_coords[pos].second] = true;
                True_elements++;
                all_coords.erase(all_coords.begin()+pos);
            }
        }

        // 6) residue part
        int mod = total_elements % (int)nBatches;
        for(int i=0;i<mod;i++)
        {
            // evenly distribute 'mod' elements to Filters
            int True_elements = 0;
            while(True_elements < 1 && all_coords.size() > 0)
            {
                std::uniform_int_distribution<int> index(0, (int)all_coords.size()-1);
                int pos = index(gen);
                (Ret[i])[all_coords[pos].first][all_coords[pos].second] = true;
                True_elements++;
                all_coords.erase(all_coords.begin()+pos);
            }
        }
        //assert(1 < 0);

        // 7) complete the rest elements
        // a helper
        // complete missing elements
        auto complete = [&](size_t required_active_elements, Filter2D& F)
        {
            int actual_active_elements = F.GetNumberOfTrueElements();
            int residue = (int)required_active_elements - actual_active_elements;
            //assert(residue >= 0); // incorrect
            if(residue < 0) return; // correct, in case number of neurons is odd number

            // first save all inactive coords
            std::vector<std::pair<int, int>> tmp;
            auto dim = F.Dimension();
            for(size_t i=0;i<dim.first;i++)
            {
                for(size_t j=0;j<dim.second;j++)
                    if(!F[i][j]) tmp.push_back(std::pair<int, int>((int)i, (int)j));
            }
            int count = 0;
            while(count < residue && tmp.size() > 0)
            {
                std::uniform_int_distribution<int> index(0, (int)tmp.size()-1);
                int pos = index(gen);
                if(!F[tmp[pos].first][tmp[pos].second])
                {
                    F[tmp[pos].first][tmp[pos].second] = true;
                    tmp.erase(tmp.begin() + pos);
                    count++;
                }
            }
        };

        for(auto &M: Ret)
            complete(total_elements*(1.-dropoutRatio), M);

        return Ret;
    }

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2768, %rsp           # imm = 0x2768
movsd %xmm0, 0x40(%rsp)
movq %rdx, %rbx
movq %rdi, %r13
movq %rsi, %rdi
callq 0x1145e
testq %rbx, %rbx
je 0x1177e
movsd 0x10052(%rip), %xmm2    # 0x21510
movsd 0x40(%rsp), %xmm1
ucomisd %xmm1, %xmm2
jbe 0x1179d
movq %rax, %r15
movq %rdx, %r12
movl %r12d, %eax
imull %r15d, %eax
movl %eax, 0x38(%rsp)
cvtsi2sd %eax, %xmm0
subsd %xmm1, %xmm2
cvtsi2sd %ebx, %xmm1
mulsd %xmm0, %xmm2
movapd %xmm2, 0x40(%rsp)
mulsd %xmm2, %xmm1
ucomisd %xmm0, %xmm1
jb 0x117bc
leaq 0x13e0(%rsp), %r14
movq %r14, %rdi
callq 0x11a0a
movq %r14, %rdi
callq 0x42b0
movl %eax, %esi
leaq 0x58(%rsp), %rdi
callq 0x131a2
andq $0x0, 0x10(%r13)
xorpd %xmm0, %xmm0
movupd %xmm0, (%r13)
leaq 0x10(%rsp), %r14
movq %rbx, 0x30(%rsp)
subq $0x1, %rbx
jb 0x1156b
movq %r14, %rdi
movq %r15, %rsi
movq %r12, %rdx
xorl %ecx, %ecx
callq 0x12a86
movq %r13, %rdi
movq %r14, %rsi
callq 0x12c88
movq %r14, %rdi
callq 0x11e36
jmp 0x11540
movq %r13, 0x28(%rsp)
leaq 0x10(%rsp), %r13
andq $0x0, 0x10(%r13)
xorpd %xmm0, %xmm0
movapd %xmm0, (%r13)
xorl %ebx, %ebx
leaq 0x8(%rsp), %r14
movapd 0x40(%rsp), %xmm0
cmpq %r15, %rbx
je 0x115c0
xorl %ebp, %ebp
cmpq %rbp, %r12
je 0x115bb
movl %ebx, 0x8(%rsp)
movl %ebp, 0xc(%rsp)
movq %r13, %rdi
movq %r14, %rsi
callq 0x12e70
incq %rbp
movapd 0x40(%rsp), %xmm0
jmp 0x11598
incq %rbx
jmp 0x11591
movl 0x38(%rsp), %eax
cltd
idivl 0x30(%rsp)
movq %rdx, 0x50(%rsp)
movq 0x28(%rsp), %rcx
movq (%rcx), %r14
movq 0x8(%rcx), %rcx
movq %rcx, 0x38(%rsp)
xorl %ecx, %ecx
testl %eax, %eax
cmovgl %eax, %ecx
movl %ecx, 0x30(%rsp)
leaq 0x8(%rsp), %r15
leaq 0x58(%rsp), %r12
leaq 0x10(%rsp), %r13
movl 0x30(%rsp), %ebx
cmpq 0x38(%rsp), %r14
je 0x11671
subl $0x1, %ebx
jb 0x1166b
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
je 0x1166b
shrq $0x3, %rax
decl %eax
andl $0x0, 0x8(%rsp)
movl %eax, 0xc(%rsp)
movq %r15, %rdi
movq %r12, %rsi
callq 0x11a60
movslq %eax, %rbp
movq 0x10(%rsp), %rax
movslq (%rax,%rbp,8), %rcx
imulq $0x28, %rcx, %rdi
addq (%r14), %rdi
movslq 0x4(%rax,%rbp,8), %rsi
callq 0x11440
orq %rdx, (%rax)
shlq $0x3, %rbp
addq 0x10(%rsp), %rbp
movq %r13, %rdi
movq %rbp, %rsi
callq 0x12b10
movapd 0x40(%rsp), %xmm0
jmp 0x11604
addq $0x18, %r14
jmp 0x115f9
xorl %ebx, %ebx
movq 0x50(%rsp), %rax
testl %eax, %eax
cmovlel %ebx, %eax
imulq $0x18, %rax, %rbp
leaq 0x8(%rsp), %r15
leaq 0x58(%rsp), %r14
leaq 0x10(%rsp), %r12
movq 0x28(%rsp), %r13
cmpq %rbx, %rbp
je 0x1170a
movq 0x18(%rsp), %rax
subq 0x10(%rsp), %rax
je 0x11704
shrq $0x3, %rax
decl %eax
andl $0x0, 0x8(%rsp)
movl %eax, 0xc(%rsp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x11a60
movq (%r13), %rcx
movslq %eax, %r13
movq 0x10(%rsp), %rax
movslq (%rax,%r13,8), %rdx
imulq $0x28, %rdx, %rdi
addq (%rcx,%rbx), %rdi
movslq 0x4(%rax,%r13,8), %rsi
callq 0x11440
orq %rdx, (%rax)
shlq $0x3, %r13
addq 0x10(%rsp), %r13
movq %r12, %rdi
movq %r13, %rsi
callq 0x12b10
movq 0x28(%rsp), %r13
movapd 0x40(%rsp), %xmm0
addq $0x18, %rbx
jmp 0x11695
leaq 0x8(%rsp), %r15
movq %r14, (%r15)
movq (%r13), %r14
movq 0x8(%r13), %rbx
cvttsd2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
subsd 0xfe2a(%rip), %xmm0     # 0x21558
cvttsd2si %xmm0, %r12
andq %rcx, %r12
orq %rax, %r12
cmpq %rbx, %r14
je 0x11752
movq %r15, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x12b16
addq $0x18, %r14
jmp 0x11739
leaq 0x10(%rsp), %rdi
callq 0x1320e
leaq 0x13e0(%rsp), %rdi
callq 0x11a8e
movq %r13, %rax
addq $0x2768, %rsp           # imm = 0x2768
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x11e52(%rip), %rdi     # 0x235d7
leaq 0x11e59(%rip), %rsi     # 0x235e5
leaq 0x11e64(%rip), %rcx     # 0x235f7
movl $0x9c, %edx
callq 0x4180
leaq 0x11e9e(%rip), %rdi     # 0x23642
leaq 0x11e3a(%rip), %rsi     # 0x235e5
leaq 0x11e45(%rip), %rcx     # 0x235f7
movl $0x9d, %edx
callq 0x4180
leaq 0x11e92(%rip), %rdi     # 0x23655
leaq 0x11e1b(%rip), %rsi     # 0x235e5
leaq 0x11e26(%rip), %rcx     # 0x235f7
movl $0xa0, %edx
callq 0x4180
movq %rax, %r14
jmp 0x1181c
jmp 0x11802
jmp 0x11802
jmp 0x11802
jmp 0x11802
movq %rax, %r14
jmp 0x11814
movq %rax, %r14
leaq 0x10(%rsp), %rdi
callq 0x11e36
jmp 0x11814
jmp 0x11802
jmp 0x11802
jmp 0x11802
movq %rax, %r14
leaq 0x10(%rsp), %rdi
callq 0x1320e
movq 0x28(%rsp), %r13
movq %r13, %rdi
callq 0x1114a
leaq 0x13e0(%rsp), %rdi
callq 0x11a8e
movq %r14, %rdi
callq 0x43b0
nop