// File: xbai0624[P]dnn/src/ConstructLayer.cpp
// Function: ConstructLayer::TransferValueFromOriginalToActive_WB()
void ConstructLayer::TransferValueFromOriginalToActive_WB()
{
    size_t nKernel = __weightMatrix.size();
    assert(nKernel == __biasVector.size());
    if(__type == LayerType::cnn || __type == LayerType::pooling) 
        assert(nKernel == __activeFlag.size());

    // a lambda funtion for cnn layer mapping original w&b matrix to active w&b matrix
    auto map_matrix_cnn = [&](Matrix &ori_M, Filter2D &filter_M)
    {
        auto dim = ori_M.Dimension();
        assert(dim == filter_M.Dimension());

        // weight matrix
        Matrix tmp(dim);
        for(size_t i=0;i<dim.first;i++)
        {
            for(size_t j=0;j<dim.second;j++){
                if(filter_M[i][j]){
                    tmp[i][j] = ori_M[i][j];
                }
                else{
                    tmp[i][j] = 0.;
                }
            }
        }
        __weightMatrixActive.push_back(tmp);
    };

    // a lambda funtion for fc layer mapping original w&b matrix to active w&b matrix
    //   to comply with Neuron design, each active row of original w&b matrix will be 
    //   taken out and then form a matrix, then filled to active w&b matrix
    //   so active w&b matrix will be composed of dimension (1, N) matrix, and then each of them will be passed to neurons
    auto map_matrix_fc = [&](Matrix &ori_M, Filter2D &filter_M)
    {
        auto dim = ori_M.Dimension();

        assert(dim.first == filter_M.Dimension().first);
        assert(filter_M.Dimension().second == 1);
        assert(__biasVector.size() == 1);

        for(size_t i=0;i<dim.first;i++)
        {
            if(!filter_M[i][0]) continue;

            // weight
            std::vector<double> act_row;
            for(size_t j=0;j<dim.second;j++)
            {
                if(__prevLayer != nullptr &&   // current layer is not input layer
                        (__prevLayer->GetType() == LayerType::fullyConnected ) // only fc layer no need for other type layers (output layer is labeled as 'fc'; input layer has no w&b matrix)
                  )
                {
                    auto & filter_prev = __prevLayer->GetActiveFlag();
                    assert(filter_prev.size() == 1);
                    if(!filter_prev[0][j][0])
                        continue;
                }
                act_row.push_back(ori_M[i][j]);
            }
            std::vector<std::vector<double>> act_M;
            act_M.push_back(act_row);
            Matrix tmp(act_M);
            __weightMatrixActive.push_back(tmp);

            // bias
            std::vector<double> act_bias;
            act_bias.push_back(__biasVector[0][i][0]);
            std::vector<std::vector<double>> act_b;
            act_b.push_back(act_bias);
            Matrix tmp_b(act_b);
            __biasVectorActive.push_back(tmp_b);
        }
    };

    // start mapping
    if(__type == LayerType::cnn || __type == LayerType::pooling)
    {
        for(size_t k=0; k<nKernel;k++)
        {
            map_matrix_cnn(__weightMatrix[k], __activeFlag[k]);
        }
        // for cnn, drop out won't change threshold
        __biasVectorActive = __biasVector; 
    }
    else if (__type == LayerType::fullyConnected || __type == LayerType::output)
    {
        map_matrix_fc(__weightMatrix[0], __activeFlag[0]);
    }

    // update active neuron coord after drop out
    if(__type == LayerType::cnn || __type == LayerType::pooling)
    {
        __activeNeuronDim = __neuronDim; // drop out not happening on neurons, so dimension stays same
    }
    else if(__type == LayerType::fullyConnected || __type == LayerType::output)
    {
        __activeNeuronDim = __neuronDim; // update active neuron dimension
        size_t active_neurons = __weightMatrixActive.size();
        __activeNeuronDim.i = active_neurons;
    }

    //std::cout<<"Debug: Layer:"<<GetID()<<" TransferValueFromOriginalToActiveWB() done."<<std::endl;
}

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x50(%rsp)
movq 0x50(%rsp), %rdi
movq %rdi, 0x18(%rsp)
addq $0x60, %rdi
callq 0x1f9c0
movq 0x18(%rsp), %rdi
movq %rax, 0x48(%rsp)
movq 0x48(%rsp), %rax
movq %rax, 0x20(%rsp)
addq $0x78, %rdi
callq 0x1f9c0
movq %rax, %rcx
movq 0x20(%rsp), %rax
cmpq %rcx, %rax
jne 0x15098
jmp 0x150b7
leaq 0x3e094(%rip), %rdi     # 0x53133
leaq 0x3d12c(%rip), %rsi     # 0x521d2
movl $0xb51, %edx            # imm = 0xB51
leaq 0x3e0a0(%rip), %rcx     # 0x53152
callq 0x4170
movq 0x18(%rsp), %rax
cmpl $0x1, 0xc(%rax)
je 0x150cd
movq 0x18(%rsp), %rax
cmpl $0x2, 0xc(%rax)
jne 0x15118
movq 0x18(%rsp), %rdi
movq 0x48(%rsp), %rax
movq %rax, 0x10(%rsp)
addq $0x108, %rdi            # imm = 0x108
callq 0x1ffd0
movq %rax, %rcx
movq 0x10(%rsp), %rax
cmpq %rcx, %rax
jne 0x150f7
jmp 0x15116
leaq 0x3e098(%rip), %rdi     # 0x53196
leaq 0x3d0cd(%rip), %rsi     # 0x521d2
movl $0xb53, %edx            # imm = 0xB53
leaq 0x3e041(%rip), %rcx     # 0x53152
callq 0x4170
jmp 0x15118
movq 0x18(%rsp), %rax
movq %rax, 0x40(%rsp)
movq %rax, 0x38(%rsp)
cmpl $0x1, 0xc(%rax)
je 0x15138
movq 0x18(%rsp), %rax
cmpl $0x2, 0xc(%rax)
jne 0x151b7
movq $0x0, 0x30(%rsp)
movq 0x30(%rsp), %rax
cmpq 0x48(%rsp), %rax
jae 0x1519d
movq 0x18(%rsp), %rdi
addq $0x60, %rdi
movq 0x30(%rsp), %rsi
callq 0x1f9e0
movq 0x18(%rsp), %rdi
movq %rax, 0x8(%rsp)
addq $0x108, %rdi            # imm = 0x108
movq 0x30(%rsp), %rsi
callq 0x1ff80
movq 0x8(%rsp), %rsi
movq %rax, %rdx
leaq 0x40(%rsp), %rdi
callq 0x152d0
movq 0x30(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x30(%rsp)
jmp 0x15141
movq 0x18(%rsp), %rdi
movq %rdi, %rsi
addq $0x78, %rsi
addq $0xf0, %rdi
callq 0x214b0
jmp 0x1520b
movq 0x18(%rsp), %rax
cmpl $0x0, 0xc(%rax)
je 0x151cd
movq 0x18(%rsp), %rax
cmpl $0x4, 0xc(%rax)
jne 0x15209
movq 0x18(%rsp), %rdi
addq $0x60, %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x1f9e0
movq 0x18(%rsp), %rdi
movq %rax, (%rsp)
addq $0x108, %rdi            # imm = 0x108
xorl %eax, %eax
movl %eax, %esi
callq 0x1ff80
movq (%rsp), %rsi
movq %rax, %rdx
leaq 0x38(%rsp), %rdi
callq 0x15560
jmp 0x1520b
movq 0x18(%rsp), %rax
cmpl $0x1, 0xc(%rax)
je 0x15221
movq 0x18(%rsp), %rax
cmpl $0x2, 0xc(%rax)
jne 0x15252
movq 0x18(%rsp), %rax
movq 0x398(%rax), %rcx
movq %rcx, 0x3b0(%rax)
movq 0x3a0(%rax), %rcx
movq %rcx, 0x3b8(%rax)
movq 0x3a8(%rax), %rcx
movq %rcx, 0x3c0(%rax)
jmp 0x152be
movq 0x18(%rsp), %rax
cmpl $0x0, 0xc(%rax)
je 0x15268
movq 0x18(%rsp), %rax
cmpl $0x4, 0xc(%rax)
jne 0x152bc
movq 0x18(%rsp), %rdi
movq 0x398(%rdi), %rax
movq %rax, 0x3b0(%rdi)
movq 0x3a0(%rdi), %rax
movq %rax, 0x3b8(%rdi)
movq 0x3a8(%rdi), %rax
movq %rax, 0x3c0(%rdi)
addq $0xd8, %rdi
callq 0x1f9c0
movq %rax, %rcx
movq 0x18(%rsp), %rax
movq %rcx, 0x28(%rsp)
movq 0x28(%rsp), %rcx
movq %rcx, 0x3b0(%rax)
jmp 0x152be
addq $0x58, %rsp
retq
nopw %cs:(%rax,%rax)