// File: /workspace/github_cpp_makefile_star2_O2/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 0x4250
movq %rax, %r12
leaq 0x788c(%rip), %rsi      # 0x2556f
leaq 0x78a4(%rip), %rdx      # 0x2558e
movq %rax, %rdi
xorl %ecx, %ecx
callq 0x16572
movl $0x490, %edi            # imm = 0x490
callq 0x4250
movq %rax, %r13
leaq 0x150(%rsp), %rsi
movq $0x3, (%rsi)
movq %r12, 0x8(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsi)
movups %xmm0, 0x20(%rsi)
movups %xmm0, 0x29(%rsi)
andl $0x0, 0x3c(%rsi)
movabsq $0x3fe0000000000000, %r14 # imm = 0x3FE0000000000000
movq %r14, 0x40(%rsi)
movl $0x2, 0x48(%rsi)
movups %xmm0, 0x50(%rsi)
movb $0x0, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
movq (%r13), %rax
movq %r13, %rdi
callq *0x10(%rax)
movl $0x490, %edi            # imm = 0x490
callq 0x4250
leaq 0xe8(%rsp), %rsi
andq $0x0, (%rsi)
movq %rax, %rbx
movq %r12, 0x8(%rsi)
movq $0x5, 0x10(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsi)
andq $0x0, 0x28(%rsi)
movabsq $0x3fb999999999999a, %r15 # imm = 0x3FB999999999999A
movq %r15, 0x30(%rsi)
movb $0x1, 0x38(%rsi)
movl $0x2, 0x3c(%rsi)
movq %r14, 0x40(%rsi)
andl $0x0, 0x48(%rsi)
movq %r15, 0x50(%rsi)
andq $0x0, 0x58(%rsi)
movb $0x0, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
movq (%rbx), %rax
movq %rbx, %rdi
movq %r13, %rsi
callq *0x1e8(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x10(%rax)
movl $0x490, %edi            # imm = 0x490
callq 0x4250
leaq 0x80(%rsp), %rsi
movq $0x4, (%rsi)
movq %r12, 0x8(%rsi)
movq $0x2, 0x10(%rsi)
andq $0x0, 0x28(%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsi)
movq %r15, 0x30(%rsi)
xorl %ecx, %ecx
movb %cl, 0x38(%rsi)
andl $0x0, 0x3c(%rsi)
movq %r14, 0x40(%rsi)
andl $0x0, 0x48(%rsi)
movq %rax, %r14
movq %r15, 0x50(%rsi)
movq $0x1, 0x58(%rsi)
movb %cl, 0x60(%rsi)
pushq $0xd
popq %rcx
movq %rsp, %rdi
rep  movsq (%rsi), %es:(%rdi)
movq %rax, %rdi
callq 0x4762
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 %r12, %rdi
callq 0x16b9a
movq %r12, %rdi
callq 0x16e5e
movq (%r13), %rax
movq %r13, %rdi
callq *0x180(%rax)
movq (%r13), %rax
movq %r13, 0x70(%rsp)
movq %r13, %rdi
callq *0x2a0(%rax)
movslq %eax, %r12
movq 0x15110(%rip), %r15     # 0x32fd8
leaq 0x76de(%rip), %rsi      # 0x255ad
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
movq %r12, %rsi
callq 0x41a0
movq %rax, %rdi
callq 0x4130
xorl %r13d, %r13d
leaq 0x76c7(%rip), %rbp      # 0x255bb
cmpq %r13, %r12
je 0x1df4c
movq %r15, %rdi
movq %rbp, %rsi
callq 0x4240
movq %rax, %rdi
movq %r13, %rsi
callq 0x41a0
movq %rax, %rdi
callq 0x4130
movq (%rbx), %rax
movq %rbx, %rdi
movl %r13d, %esi
callq *0x28(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
movl %r13d, %esi
callq *0x30(%rax)
movq (%r14), %rax
movq %r14, %rdi
movl %r13d, %esi
callq *0x28(%rax)
movq (%r14), %rax
movq %r14, %rdi
movl %r13d, %esi
callq *0x30(%rax)
incq %r13
jmp 0x1def4
xorl %r13d, %r13d
movq 0x15082(%rip), %rbp     # 0x32fd8
leaq 0x767b(%rip), %r15      # 0x255d8
cmpq %r13, %r12
je 0x1dff0
movq %rbp, %rdi
movq %r15, %rsi
callq 0x4240
movq %rax, %rdi
movq %r13, %rsi
callq 0x41a0
movq %rax, %rdi
leaq 0x767d(%rip), %rsi      # 0x25603
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq 0x70(%rsp), %rdi
movq %r13, %rsi
callq 0x1e218
movq %rbx, %rdi
movq %r13, %rsi
callq 0x1e218
movq %r14, %rdi
movq %r13, %rsi
callq 0x1e218
movq %rbp, %rdi
movq %r15, %rsi
callq 0x4240
movq %rax, %rdi
movq %r13, %rsi
callq 0x41a0
movq %rax, %rdi
leaq 0x7655(%rip), %rsi      # 0x2562b
callq 0x4240
movq %rax, %rdi
callq 0x4130
callq 0x42c0
incq %r13
jmp 0x1df5d
movq 0x14fe1(%rip), %r15     # 0x32fd8
leaq 0x7653(%rip), %rsi      # 0x25651
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq 0x70(%rsp), %rdi
callq 0x1e42e
movq %rbx, %rdi
callq 0x1e42e
movq %r14, %rdi
callq 0x1e42e
xorl %r13d, %r13d
leaq 0x7656(%rip), %rbp      # 0x25688
cmpq %r13, %r12
je 0x1e072
movq %r15, %rdi
movq %rbp, %rsi
callq 0x4240
movq %rax, %rdi
movq %r13, %rsi
callq 0x41a0
movq %rax, %rdi
callq 0x4130
movq (%r14), %rax
movq %r14, %rdi
movl %r13d, %esi
callq *0x38(%rax)
movq (%rbx), %rax
movq %rbx, %rdi
movl %r13d, %esi
callq *0x38(%rax)
incq %r13
jmp 0x1e032
movq 0x14f5f(%rip), %r15     # 0x32fd8
leaq 0x7626(%rip), %rsi      # 0x256a6
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq %r14, %rdi
callq 0x1e64a
leaq 0x7899(%rip), %rsi      # 0x25938
movq %r15, %rdi
callq 0x4240
movq %rax, %r12
movq (%r14), %rax
movq %r14, %rdi
callq *0x298(%rax)
movq %r12, %rdi
movl %eax, %esi
callq 0x43a0
leaq 0x6e3b(%rip), %rsi      # 0x24f02
movq %rax, %rdi
callq 0x4240
movq %rax, %r12
movq (%r14), %rax
movq %r14, %rdi
callq *0x250(%rax)
leaq 0x7c(%rsp), %rsi
movl %eax, (%rsi)
movq %r12, %rdi
callq 0x172e0
movq %rax, %rdi
callq 0x4130
leaq 0x7728(%rip), %rsi      # 0x25824
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq (%r14), %rax
movq %r14, %rdi
callq *0x230(%rax)
movq (%rax), %r12
movq 0x8(%rax), %r13
cmpq %r13, %r12
je 0x1e13d
movq %r15, %rdi
movq %r12, %rsi
callq 0x18551
movq %rax, %rdi
callq 0x4130
addq $0x18, %r12
jmp 0x1e11f
movq 0x14e94(%rip), %r15     # 0x32fd8
leaq 0x76ed(%rip), %rsi      # 0x25838
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
movq (%r14), %rax
movq %r14, %rdi
callq *0x238(%rax)
movq (%rax), %r12
movq 0x8(%rax), %r13
cmpq %r13, %r12
je 0x1e18c
movq %r15, %rdi
movq %r12, %rsi
callq 0x18551
movq %rax, %rdi
callq 0x4130
addq $0x18, %r12
jmp 0x1e16e
movq %rbx, %rdi
callq 0x1e64a
movq 0x14e3d(%rip), %r15     # 0x32fd8
leaq 0x7545(%rip), %rsi      # 0x256e7
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
leaq 0x754f(%rip), %rsi      # 0x25708
movq %r15, %rdi
callq 0x4240
movq %rax, %rdi
callq 0x4130
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
movq %rax, %r15
movq %r14, %r12
jmp 0x1e208
movq %rax, %r15
movq %rbx, %r12
jmp 0x1e208
movq %rax, %r15
movq %r13, %r12
jmp 0x1e208
movq %rax, %r15
movq %r12, %rdi
callq 0x4220
movq %r15, %rdi
callq 0x43b0