// File: /workspace/github_cpp_makefile_star2_O2/xbai0624[P]dnn/src/Network.cpp
// Function: Network::ConstructLayers(TrainingType)
void Network::ConstructLayers(TrainingType _training_type) // test purelly fully connected, deep network, 100 layers
{
    // Network structure: {Image->Input->FC->FC->FC->Output}
    TrainingType training_type = _training_type;
    training_type = TrainingType::NewTraining;
    double learning_rate = 0.1;

    // 1) Data interface, this is a tool class, for data prepare
    DataInterface *data_interface = new DataInterface("simulation_data/data_signal_train.dat", "simulation_data/data_cosmic_train.dat", LayerDimension::_1D, std::pair<int, int>(900, 1), 200);

    // 3) input layer   ID=0
    LayerParameterList p_list0(LayerType::input, LayerDimension::_1D, data_interface, 0, 0, 
            std::pair<size_t, size_t>(0, 0), learning_rate, false, 0, 0, Regularization::Undefined, 0, ActuationFuncType::Undefined, training_type, false);
    Layer* layer_input = new ConstructLayer(p_list0);
    // NOTE: a data_interface class pointer must be passed to input layer before calling input_layer->Init() function
    //       because Initialization rely on data_interface
    layer_input->Init();

    // 4) 49 middle layers: fc layer 
    const int NLayer = 20;
    Layer *l_mid[NLayer];
    // layer 0
    LayerParameterList p_list1(LayerType::fullyConnected, LayerDimension::_1D, data_interface, 890, 0, 
            std::pair<size_t, size_t>(0, 0), learning_rate, false, 2, 0.5, Regularization::L2, 0.1, ActuationFuncType::Relu, training_type, true);
    l_mid[0] = new ConstructLayer(p_list1);
    l_mid[0]->SetPrevLayer(layer_input);
    l_mid[0]->Init();
    // layer 1 - layer 46
    for(int i=1;i<NLayer;i++)
    {
        int n_neurons = 890 - ((890-4)/(NLayer-1))*i;
        LayerParameterList p_list_mid(LayerType::fullyConnected, LayerDimension::_1D, data_interface, n_neurons, 0, 
                std::pair<size_t, size_t>(0, 0), learning_rate, false, 2, 0.5, Regularization::L2, 0.1, ActuationFuncType::Relu, training_type, true);
        l_mid[i] = new ConstructLayer(p_list_mid);
        l_mid[i]->SetPrevLayer(l_mid[i-1]);
        l_mid[i]->Init();
    }


    // 5) output layer ID = 7
    LayerParameterList p_list_output(LayerType::output, LayerDimension::_1D, data_interface, 2, 0, 
            std::pair<size_t, size_t>(0, 0), learning_rate, false, 0, 0., Regularization::L2, 0.1, ActuationFuncType::SoftMax, training_type, false);
    Layer* layer_output = new ConstructLayer(p_list_output);
    layer_output -> SetPrevLayer(l_mid[NLayer-1]);
    layer_output -> Init();

    // 6) connect all layers; SetNextLayer must be after all layers have finished initialization
    //                        input layer not needed to set, input layer has no update on w & b
    //                        input layer is just for data transfer (prepare)
    //l1->SetNextLayer(l2);
    //l2->SetNextLayer(l3);
    //l3->SetNextLayer(layer_output); // This line is ugly, to be improved
    for(int i=0;i<NLayer-1;i++)
        l_mid[i]->SetNextLayer(l_mid[i+1]);
    l_mid[NLayer-1]->SetNextLayer(layer_output);

    // 7) save all constructed layers
    __inputLayer = layer_input;
    __outputLayer = layer_output;
    //__middleAndOutputLayers.push_back(l1); // must be pushed in order
    //__middleAndOutputLayers.push_back(l2); // must be pushed in order
    //__middleAndOutputLayers.push_back(l3);
    //__middleAndOutputLayers.push_back(layer_output);
    for(int i=0;i<NLayer;i++)
        __middleAndOutputLayers.push_back(l_mid[i]);
    __middleAndOutputLayers.push_back(layer_output);
    //cout<<"total number of layers: "<<__middleAndOutputLayers.size()<<endl;
    __dataInterface = data_interface;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2c8, %rsp            # imm = 0x2C8
movq %rdi, %rbx
movl $0xc8, %edi
callq 0x4250
movq %rax, %r12
leaq 0x97f5(%rip), %rsi      # 0x2499b
leaq 0x9814(%rip), %rdx      # 0x249c1
movabsq $0x100000384, %r8       # imm = 0x100000384
movq %rax, %rdi
xorl %ecx, %ecx
movl $0xc8, %r9d
callq 0x16a22
movl $0x490, %edi            # imm = 0x490
callq 0x4250
leaq 0x260(%rsp), %rsi
movq $0x3, (%rsi)
movq %r12, 0x8(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsi)
movups %xmm0, 0x20(%rsi)
movabsq $0x3fb999999999999a, %r15 # imm = 0x3FB999999999999A
movq %r15, 0x30(%rsi)
xorl %ecx, %ecx
movb %cl, 0x38(%rsi)
andl $0x0, 0x3c(%rsi)
andq $0x0, 0x40(%rsi)
movl $0x2, 0x48(%rsi)
andq $0x0, 0x50(%rsi)
movq %rax, %r13
movq $0x4, 0x58(%rsi)
movb %cl, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
movq %rbx, 0x78(%rsp)
movq (%r13), %rax
movq %r13, %rdi
callq *0x10(%rax)
movl $0x490, %edi            # imm = 0x490
callq 0x4250
leaq 0x1f8(%rsp), %rsi
andq $0x0, (%rsi)
movq %r12, 0x8(%rsi)
movq $0x37a, 0x10(%rsi)      # imm = 0x37A
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsi)
andq $0x0, 0x28(%rsi)
movq %r15, 0x30(%rsi)
movb $0x0, 0x38(%rsi)
movl $0x2, 0x3c(%rsi)
movabsq $0x3fe0000000000000, %rcx # imm = 0x3FE0000000000000
movq %rcx, 0x40(%rsi)
andl $0x0, 0x48(%rsi)
movq %rax, %r14
movq %r15, 0x50(%rsi)
movq $0x3, 0x58(%rsi)
movb $0x1, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
leaq 0xf8(%rsp), %rbx
movq %r14, -0x8(%rbx)
movq (%r14), %rax
movq %r14, %rdi
movq %r13, 0x70(%rsp)
movq %r13, %rsi
callq *0x1e8(%rax)
movq (%r14), %rax
movq %r14, %rdi
callq *0x10(%rax)
leaq 0xa0(%rsp), %r13
movl $0x34c, %ebp            # imm = 0x34C
movq %r14, %r15
movq %r12, 0x68(%rsp)
movl $0x490, %edi            # imm = 0x490
cmpq $-0x1e, %rbp
je 0x1b3d9
callq 0x4250
andq $0x0, 0x88(%rsp)
movq %r12, 0x90(%rsp)
movq %rbp, 0x98(%rsp)
andq $0x0, 0x10(%r13)
xorps %xmm0, %xmm0
movups %xmm0, (%r13)
movabsq $0x3fb999999999999a, %rcx # imm = 0x3FB999999999999A
movq %rcx, 0xb8(%rsp)
movb $0x0, 0xc0(%rsp)
movl $0x2, 0xc4(%rsp)
movabsq $0x3fe0000000000000, %rdx # imm = 0x3FE0000000000000
movq %rdx, 0xc8(%rsp)
andl $0x0, 0xd0(%rsp)
movq %rax, %r12
movq %rcx, 0xd8(%rsp)
movq $0x3, 0xe0(%rsp)
movb $0x1, 0xe8(%rsp)
pushq $0xd
popq %rcx
movq %rsp, %rdi
leaq 0x88(%rsp), %rsi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
movq %r12, (%rbx)
movq (%r12), %rax
movq %r12, %rdi
movq %r15, %rsi
callq *0x1e8(%rax)
movq (%r12), %rax
movq %r12, %rdi
callq *0x10(%rax)
addq $-0x2e, %rbp
addq $0x8, %rbx
movq %r12, %r15
movq 0x68(%rsp), %r12
jmp 0x1b2f6
callq 0x4250
movq %rax, %r13
leaq 0x190(%rsp), %rsi
movq $0x4, (%rsi)
movq %r12, 0x8(%rsi)
movq $0x2, 0x10(%rsi)
xorps %xmm0, %xmm0
andq $0x0, 0x28(%rsi)
movups %xmm0, 0x18(%rsi)
movabsq $0x3fb999999999999a, %rcx # imm = 0x3FB999999999999A
movq %rcx, 0x30(%rsi)
xorl %eax, %eax
movb %al, 0x38(%rsi)
movups %xmm0, 0x3c(%rsi)
movq %rcx, 0x50(%rsi)
movq $0x1, 0x58(%rsi)
movb %al, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %r13, %rdi
callq 0x4762
movq %r13, 0x80(%rsp)
movq 0x188(%rsp), %r15
movq (%r13), %rax
movq %r13, %rdi
movq %r15, %rsi
callq *0x1e8(%rax)
movq (%r13), %rax
movq %r13, %rdi
callq *0x10(%rax)
pushq $0x1
popq %rbx
cmpq $0x14, %rbx
je 0x1b491
movq 0xf0(%rsp,%rbx,8), %r12
movq (%r14), %rax
movq %r14, %rdi
movq %r12, %rsi
callq *0x1f0(%rax)
incq %rbx
movq %r12, %r14
jmp 0x1b46c
movq (%r15), %rax
movq %r15, %rdi
movq %r13, %rsi
callq *0x1f0(%rax)
movq 0x78(%rsp), %r15
movq 0x70(%rsp), %rax
movq %rax, 0x18(%r15)
movq %r13, 0x20(%r15)
xorl %ebx, %ebx
movq 0x68(%rsp), %r14
cmpq $0xa0, %rbx
je 0x1b4db
leaq (%rsp,%rbx), %rsi
addq $0xf0, %rsi
movq %r15, %rdi
callq 0x1ba48
addq $0x8, %rbx
jmp 0x1b4b9
leaq 0x80(%rsp), %rsi
movq %r15, %rdi
callq 0x1ba48
movq %r14, 0x28(%r15)
addq $0x2c8, %rsp            # imm = 0x2C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x1b50b
movq %rax, %r15
movq %r14, %rdi
jmp 0x1b51b
movq %rax, %r15
movq %r13, %rdi
jmp 0x1b51b
jmp 0x1b515
movq %rax, %r15
movq %r12, %rdi
callq 0x4220
movq %r15, %rdi
callq 0x43b0