// File: /workspace/github_cpp_makefile_star2_O1/xbai0624[P]dnn/src/UnitTest.cpp
// Function: UnitTest::TestDNN()
void UnitTest::TestDNN()
{
    // setup a 1D data interface
    DataInterface *data_interface = new DataInterface("unit_test_data/data_signal.dat", "unit_test_data/data_cosmic.dat", LayerDimension::_1D);

    // setup a 1D input layer
    LayerParameterList p_list0(LayerType::input, LayerDimension::_1D, data_interface, 0, 0, 
            std::pair<size_t, size_t>(0, 0), 0, false, 0, 0.5, Regularization::Undefined, 0, ActuationFuncType::Sigmoid, TrainingType::NewTraining, 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();

    // setup a FC layer
    LayerParameterList p_list3(LayerType::fullyConnected, LayerDimension::_1D, data_interface, 5, 0, 
            std::pair<size_t, size_t>(0, 0), 0.1, true, 2, 0.5, Regularization::L2, 0.1, ActuationFuncType::Sigmoid, TrainingType::NewTraining, false);
    Layer *l3 = new ConstructLayer(p_list3);
    l3->SetPrevLayer(layer_input);
    l3->Init();

    // setup an output layer
    LayerParameterList p_list_output(LayerType::output, LayerDimension::_1D, data_interface, 2, 0, 
            std::pair<size_t, size_t>(0, 0), 0.1, false, 0, 0.5, Regularization::L2, 0.1, ActuationFuncType::SoftMax, TrainingType::NewTraining, false);
    Layer* layer_output = new ConstructLayer(p_list_output);
    layer_output -> SetPrevLayer(l3);
    layer_output -> Init();

    // connect all  layers
    l3->SetNextLayer(layer_output); // This line is ugly, to be improved


    // loop epoch
    for(int epoch = 0;epoch<1;epoch++) // only 1 epoch
    { //
        // loop batch
        for(int nbatch = 0;nbatch<1;nbatch++) // only 1 batch
        { //

            // test start here
            l3->BatchInit();
            layer_output->BatchInit();

            data_interface -> GetNewBatchData();
            data_interface -> GetNewBatchLabel();
            layer_input -> FillBatchDataToInputLayerA();

            size_t sample_size = layer_input->GetBatchSize();
            cout<<"sample size: "<<sample_size<<endl;

            auto show_layer_in_forward = [&](Layer *l, size_t id)
            {
                // show full a image
                cout<<"===layer=layer=layer=layer=layer=layer=layer=layer=layer==="<<endl;
                cout<<"layer id: "<<l->GetID()<<", "<<l->GetType()<<endl;

                cout<<"original w Matrix: "<<endl;
                for(auto &i: *(l->GetWeightMatrixOriginal()))
                    cout<<i<<endl;

                //cout<<"active w Matrix: "<<endl;
                //for(auto &i: *(l->GetWeightMatrix()))
                //    cout<<i<<endl;

                cout<<"original bias vector: "<<endl;
                for(auto &i: *(l->GetBiasVectorOriginal()))
                    cout<<i<<endl;

                //cout<<"active bias vector: "<<endl;
                //for(auto &i: *(l->GetBiasVector()))
                //    cout<<i<<endl;

                //cout<<"active Z images: "<<endl;
                //if((l->GetImagesActiveZ()).size() > 0)
                //    for(auto &i: (l->GetImagesActiveZ())[id].OutputImageFromKernel)
                //		cout<<i<<endl;

                cout<<"full Z images: "<<endl;
                if((l->GetImagesFullZ()).size()>0)
                    for(auto &i: (l->GetImagesFullZ())[id].OutputImageFromKernel)
                        cout<<i<<endl;

                //cout<<"active a images: "<<endl;
                //if((l->GetImagesActiveA()).size() > 0)
                //    for(auto &i: (l->GetImagesActiveA())[id].OutputImageFromKernel)
                //	cout<<i<<endl;

                cout<<"full a images: "<<endl;
                if((l->GetImagesFullA()).size() > 0)
                    for(auto &i: (l->GetImagesFullA())[id].OutputImageFromKernel)
                        cout<<i<<endl;
            };


            // loop sample forward direction
            for(size_t sample_id = 0;sample_id < sample_size;sample_id++)
            {
                cout<<"forward propagation sample: "<<sample_id<<endl;
                l3->ForwardPropagate_Z_ForSample(sample_id);
                l3->ForwardPropagate_SigmaPrimeAndA_ForSample(sample_id);
                layer_output->ForwardPropagate_Z_ForSample(sample_id);
                layer_output->ForwardPropagate_SigmaPrimeAndA_ForSample(sample_id);
            }

            //==============================================================
            // use your eyes here.... check forward propagation
            //==============================================================
            for(size_t id=0;id<sample_size;id++)
            {
                // check for each sample
                cout<<"%%%%%%%%%%%%%%%%%%%%%%% checking sample : "<<id<<" start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"<<endl;
                show_layer_in_forward(layer_input, id);
                show_layer_in_forward(l3, id);
                show_layer_in_forward(layer_output, id);
                cout<<"%%%%%%%%%%%%%%%%%%%%%%% checking sample : "<<id<<" end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"<<endl;
                getchar();
            }
            // check everything is saved properly after batch finished
            cout<<"................ Check Batch Results ................."<<endl;
            auto check_forward_batch_results= [&](Layer* layer) 
            {
                cout<<"############## layer: "<<layer->GetID()<<" ##############"<<endl;
                cout<<"--------  full image Z: -------  "<<endl;
                for(auto &i: layer->GetImagesFullZ())
                {
                    cout<<"sample:"<<endl;
                    for(auto &j: i.OutputImageFromKernel)
                    {
                        cout<<"    kernel: "<<endl;
                        cout<<j<<endl;
                    }
                }

                cout<<"--------  full image A: -------  "<<endl;
                for(auto &i: layer->GetImagesFullA())
                {
                    cout<<"sample:"<<endl;
                    for(auto &j: i.OutputImageFromKernel)
                    {
                        cout<<"    kernel: "<<endl;
                        cout<<j<<endl;
                    }
                }

                cout<<"--------  full image SigmaPrime: -------  "<<endl;
                for(auto &i: layer->GetImagesFullSigmaPrime())
                {
                    cout<<"sample:"<<endl;
                    for(auto &j: i.OutputImageFromKernel)
                    {
                        cout<<"    kernel: "<<endl;
                        cout<<j<<endl;
                    }
                }

            };

            check_forward_batch_results(layer_input);
            check_forward_batch_results(l3);
            check_forward_batch_results(layer_output);

            // loop sample backward direction
            for(size_t sample_id = 0;sample_id < sample_size;sample_id++)
            {
                cout<<"backward propagation sample: "<<sample_id<<endl;
                layer_output->BackwardPropagateForSample(sample_id);
                l3->BackwardPropagateForSample(sample_id);
            }

            // show backward batch results
            auto show_layer_in_backward = [&](Layer* layer)
            {
                cout<<"===layer=layer=layer=layer=layer=layer=layer=layer=layer==="<<endl;
                cout<<"layer id: "<<layer->GetID()<<", "<<layer->GetType()<<endl;

                cout<<"--------  full image Delta: -------  "<<endl;
                for(auto &i: layer->GetImagesFullDelta())
                {
                    cout<<"sample:"<<endl;
                    for(auto &j: i.OutputImageFromKernel)
                    {
                        cout<<"    kernel: "<<endl;
                        cout<<j<<endl;
                    }
                }
            };

            auto print_wb_matrix =[&](Layer *l)
            {
                cout<<"W&B matrix of layer id: "<<l->GetID()<<", "<<l->GetType()<<endl;
                cout<<"original w Matrix: "<<endl;
                for(auto &i: *(l->GetWeightMatrixOriginal()))
                    cout<<i<<endl;

                cout<<"original bias vector: "<<endl;
                for(auto &i: *(l->GetBiasVectorOriginal()))
                    cout<<i<<endl;
            };

            //==============================================================
            //     use your eyes here.... check backward propagation
            //==============================================================
            cout<<"######################### BACKWARDCHECK ########################"<<endl;
            show_layer_in_backward(layer_output);
            print_wb_matrix(layer_output);
            show_layer_in_backward(l3);


            // check weights and bias update
            cout<<"show l3 previous layer a image: "<<endl;
            cout<<"show l3 layer delta image: "<<endl;
            l3->UpdateWeightsAndBias();

            layer_output->UpdateWeightsAndBias();


        } //
    } //
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1b8, %rsp            # imm = 0x1B8
movl $0xc8, %edi
callq 0x4270
movq %rax, %r15
leaq 0x8cea(%rip), %rsi      # 0x2b5ff
leaq 0x8d02(%rip), %rdx      # 0x2b61e
movq %rax, %rdi
xorl %ecx, %ecx
callq 0x191e4
movl $0x490, %edi            # imm = 0x490
callq 0x4270
movq %rax, %r14
leaq 0x150(%rsp), %rsi
movq $0x3, (%rsi)
movq %r15, 0x8(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsi)
movups %xmm0, 0x20(%rsi)
movups %xmm0, 0x29(%rsi)
movl $0x0, 0x3c(%rsi)
movabsq $0x3fe0000000000000, %r12 # imm = 0x3FE0000000000000
movq %r12, 0x40(%rsi)
movl $0x2, 0x48(%rsi)
movups %xmm0, 0x50(%rsi)
movb $0x0, 0x60(%rsi)
movl $0xd, %ecx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4ae4
movq (%r14), %rax
movq %r14, %rdi
callq *0x10(%rax)
movl $0x490, %edi            # imm = 0x490
callq 0x4270
movq %rax, %rbx
xorl %r13d, %r13d
leaq 0xe8(%rsp), %rsi
movq %r13, (%rsi)
movq %r15, 0x8(%rsi)
movq $0x5, 0x10(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsi)
movq %r13, 0x28(%rsi)
movabsq $0x3fb999999999999a, %rbp # imm = 0x3FB999999999999A
movq %rbp, 0x30(%rsi)
movb $0x1, 0x38(%rsi)
movl $0x2, 0x3c(%rsi)
movq %r12, 0x40(%rsi)
movl $0x0, 0x48(%rsi)
movq %rbp, 0x50(%rsi)
movq %r13, 0x58(%rsi)
movb $0x0, 0x60(%rsi)
movl $0xd, %ecx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4ae4
movq (%rbx), %rax
movq %rbx, %rdi
movq %r14, %rsi
callq *0x1e8(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movl $0x490, %edi            # imm = 0x490
callq 0x4270
movq %r14, 0x70(%rsp)
movq %rax, %r14
leaq 0x80(%rsp), %rsi
movq $0x4, (%rsi)
movq %r15, 0x8(%rsi)
movq $0x2, 0x10(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsi)
movq $0x0, 0x28(%rsi)
movq %rbp, 0x30(%rsi)
movb %r13b, 0x38(%rsi)
movl %r13d, 0x3c(%rsi)
movq %r12, 0x40(%rsi)
movl %r13d, 0x48(%rsi)
movq %rbp, 0x50(%rsi)
movq $0x1, 0x58(%rsi)
movb %r13b, 0x60(%rsi)
movl $0xd, %ecx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4ae4
movq (%r14), %rax
movq %r14, %rdi
movq %rbx, %rsi
callq *0x1e8(%rax)
movq (%r14), %rax
movq %r14, %rdi
callq *0x10(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
movq %r14, %rsi
callq *0x1f0(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x88(%rax)
movq (%r14), %rax
movq %r14, %rdi
callq *0x88(%rax)
movq %r15, %rdi
callq 0x19948
movq %r15, %rdi
callq 0x19c74
movq 0x70(%rsp), %r15
movq (%r15), %rax
movq %r15, %rdi
callq *0x180(%rax)
movq (%r15), %rax
movq %r15, %rdi
callq *0x2a0(%rax)
movl %eax, 0x78(%rsp)
movslq %eax, %r13
movq 0x144c9(%rip), %r15     # 0x36fd8
leaq 0x8b27(%rip), %rsi      # 0x2b63d
movl $0xd, %edx
movq %r15, %rdi
callq 0x4280
movq %r15, %rdi
movq %r13, %rsi
callq 0x4180
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
testl %r13d, %r13d
movq %rbx, 0x68(%rsp)
je 0x22cfa
xorl %r15d, %r15d
movq 0x14468(%rip), %r12     # 0x36fd8
movq 0x68(%rsp), %rbx
movl $0x1c, %edx
movq %r12, %rdi
leaq 0x8ac7(%rip), %rsi      # 0x2b64b
callq 0x4280
movq %r12, %rdi
movq %r15, %rsi
callq 0x4180
movq %rax, %rbp
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %rbp, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq (%rbx), %rax
movq %rbx, %rdi
movl %r15d, %esi
callq *0x28(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
movl %r15d, %esi
callq *0x30(%rax)
movq (%r14), %rax
movq %r14, %rdi
movl %r15d, %esi
callq *0x28(%rax)
movq (%r14), %rax
movq %r14, %rdi
movl %r15d, %esi
callq *0x30(%rax)
incq %r15
cmpq %r15, %r13
jne 0x22b75
xorl %ebp, %ebp
movq 0x143d5(%rip), %r15     # 0x36fd8
movl $0x2a, %edx
movq %r15, %rdi
movq %r13, %rbx
leaq 0x8a53(%rip), %r13      # 0x2b668
movq %r13, %rsi
callq 0x4280
movq %r15, %rdi
movq %rbp, %rsi
callq 0x4180
movq %rax, %r12
movl $0x27, %edx
movq %rax, %rdi
leaq 0x8a59(%rip), %rsi      # 0x2b693
callq 0x4280
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r12, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq 0x70(%rsp), %rdi
movq %rbp, %rsi
callq 0x230ac
movq 0x68(%rsp), %rdi
movq %rbp, %rsi
callq 0x230ac
movq %r14, %rdi
movq %rbp, %rsi
callq 0x230ac
movl $0x2a, %edx
movq %r15, %rdi
movq %r13, %rsi
movq %rbx, %r13
callq 0x4280
movq %r15, %rdi
movq %rbp, %rsi
callq 0x4180
movq %rax, %r12
movl $0x25, %edx
movq %rax, %rdi
leaq 0x89ff(%rip), %rsi      # 0x2b6bb
callq 0x4280
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r12, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
callq 0x42e0
incq %rbp
cmpq %rbp, %rbx
jne 0x22c03
leaq 0x89e0(%rip), %rsi      # 0x2b6e1
movl $0x36, %edx
movq 0x142cb(%rip), %r15     # 0x36fd8
movq %r15, %rdi
callq 0x4280
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq 0x70(%rsp), %rdi
callq 0x23440
movq 0x68(%rsp), %rbx
movq %rbx, %rdi
callq 0x23440
movq %r14, %rdi
callq 0x23440
cmpl $0x0, 0x78(%rsp)
je 0x22dd5
xorl %r15d, %r15d
movq 0x1426c(%rip), %r12     # 0x36fd8
movl $0x1d, %edx
movq %r12, %rdi
leaq 0x899d(%rip), %rsi      # 0x2b718
callq 0x4280
movq %r12, %rdi
movq %r15, %rsi
callq 0x4180
movq %rax, %rbp
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbp, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %rbp, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq (%r14), %rax
movq %r14, %rdi
movl %r15d, %esi
callq *0x38(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
movl %r15d, %esi
callq *0x38(%rax)
incq %r15
cmpq %r15, %r13
jne 0x22d6c
leaq 0x895a(%rip), %rsi      # 0x2b736
movl $0x40, %edx
movq 0x141f0(%rip), %r12     # 0x36fd8
movq %r12, %rdi
callq 0x4280
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r12, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq %r14, %rdi
callq 0x2385a
leaq 0x8ba1(%rip), %rsi      # 0x2b9c8
movl $0x18, %edx
movq %r12, %rdi
callq 0x4280
movq (%r14), %rax
movq %r14, %rdi
callq *0x298(%rax)
movq %r12, %rdi
movl %eax, %esi
callq 0x43c0
movq %rax, %r15
leaq 0x813e(%rip), %rsi      # 0x2af92
movl $0x2, %edx
movq %rax, %rdi
callq 0x4280
movq (%r14), %rax
movq %r14, %rdi
callq *0x250(%rax)
leaq 0x7c(%rsp), %rsi
movl %eax, (%rsi)
movq %r15, %rdi
callq 0x1a124
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
leaq 0x8a07(%rip), %rsi      # 0x2b8b4
movl $0x13, %edx
movq %r12, %rdi
callq 0x4280
movq (%r12), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r12, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq (%r14), %rax
movq %r14, %rdi
callq *0x230(%rax)
movq (%rax), %r15
movq 0x8(%rax), %rbp
cmpq %rbp, %r15
je 0x22f3f
movq 0x140d7(%rip), %r12     # 0x36fd8
movq %r12, %rdi
movq %r15, %rsi
callq 0x1bb59
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r13, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
addq $0x18, %r15
cmpq %rbp, %r15
jne 0x22f01
leaq 0x8982(%rip), %rsi      # 0x2b8c8
movl $0x16, %edx
movq 0x14086(%rip), %r15     # 0x36fd8
movq %r15, %rdi
callq 0x4280
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq (%r14), %rax
movq %r14, %rdi
callq *0x238(%rax)
movq (%rax), %r15
movq 0x8(%rax), %rbp
cmpq %rbp, %r15
je 0x22fde
movq 0x14038(%rip), %r12     # 0x36fd8
movq %r12, %rdi
movq %r15, %rsi
callq 0x1bb59
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r13, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
addq $0x18, %r15
cmpq %rbp, %r15
jne 0x22fa0
movq %rbx, %rdi
callq 0x2385a
leaq 0x878a(%rip), %rsi      # 0x2b777
movl $0x20, %edx
movq 0x13fdf(%rip), %r15     # 0x36fd8
movq %r15, %rdi
callq 0x4280
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
leaq 0x8769(%rip), %rsi      # 0x2b798
movl $0x1b, %edx
movq %r15, %rdi
callq 0x4280
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4250
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4190
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x50(%rax)
movq (%r14), %rax
movq %r14, %rdi
callq *0x50(%rax)
addq $0x1b8, %rsp            # imm = 0x1B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x23091
movq %rax, %r12
movq %rbx, %r15
jmp 0x2309c
movq %rax, %r12
movq %r14, %r15
jmp 0x2309c
movq %rax, %r12
movq %r15, %rdi
callq 0x4230
movq %r12, %rdi
callq 0x43e0