// File: btbujiangjun[P]abcdl/src/cnn/CNN.cpp
// Function: abcdl::cnn::CNN::train(abcdl::algebra::MatrixSet<float> const&, abcdl::algebra::MatrixSet<float> const&, abcdl::algebra::MatrixSet<float> const&, abcdl::algebra::MatrixSet<float> const&)
void CNN::train(const abcdl::algebra::MatSet& train_data,
                const abcdl::algebra::MatSet& train_label,
                const abcdl::algebra::MatSet& test_data,
                const abcdl::algebra::MatSet& test_label){
	LOG(INFO) << "cnn train starting...";

	CHECK(train_data.size() == train_label.size() &&
       test_data.size() == test_label.size() &&
       train_data.rows() == test_data.rows() &&
       train_data.cols() == test_data.cols());
    if(!check(train_data.rows(), train_data.cols())){
        return;
    }
    
    auto now = []{return std::chrono::system_clock::now();};
    auto time_diff = [](std::chrono::time_point<std::chrono::system_clock> end) -> long long int {
        return static_cast<long long int>((std::chrono::system_clock::now() - end).count());
    };

    size_t num_train_data = train_data.size();
    size_t num_test_data = test_data.size();
    abcdl::utils::Shuffler shuffler(num_train_data);

    for(size_t i = 1; i <= _epoch; i++){
        auto start_time = now();
        shuffler.shuffle();

        for(size_t j = 0; j != num_train_data; j++){
            forward(train_data[shuffler.get(j)]);
            backward(train_label[shuffler.get(j)]);

            if(j % _batch_size  == _batch_size - 1 || j == num_train_data - 1){
                update_gradient(j % _batch_size + 1, _alpha);
            }

            if(j % 100 == 0){
                printf("Epoch[%ld][%ld/%ld]training...\r", i, j, num_train_data);
            }
        }//end per epoch

        printf("Epoch[%ld] train run time: [%lld] ms\n", i, time_diff(start_time));

        auto evaluate_time = now();
	    if(num_test_data > 0){
            printf("Epoch[%ld] [%ld/%ld] predict run time:[%lld] ms\n", i, evaluate(test_data, test_label), num_test_data, time_diff(evaluate_time));
	    }
    }
}

// Assembly:
subq $0x4a8, %rsp            # imm = 0x4A8
movq %rdi, 0x4a0(%rsp)
movq %rsi, 0x498(%rsp)
movq %rdx, 0x490(%rsp)
movq %rcx, 0x488(%rsp)
movq %r8, 0x480(%rsp)
movq 0x4a0(%rsp), %rax
movq %rax, 0x98(%rsp)
leaq 0x61b6b(%rip), %rsi     # 0x8cfb1
leaq 0x2f8(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
movl $0x22, %edx
xorl %ecx, %ecx
callq 0x86270
movq 0xa0(%rsp), %rdi
leaq 0x61c00(%rip), %rsi     # 0x8d071
callq 0x2c530
jmp 0x2b478
leaq 0x2f8(%rsp), %rdi
callq 0x86630
movq 0x498(%rsp), %rdi
callq 0x2c560
movq %rax, 0x88(%rsp)
movq 0x490(%rsp), %rdi
callq 0x2c560
movq 0x88(%rsp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, 0x97(%rsp)
jne 0x2b568
movq 0x488(%rsp), %rdi
callq 0x2c560
movq %rax, 0x80(%rsp)
movq 0x480(%rsp), %rdi
callq 0x2c560
movq 0x80(%rsp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, 0x97(%rsp)
jne 0x2b568
movq 0x498(%rsp), %rdi
callq 0x2c570
movq %rax, 0x78(%rsp)
movq 0x488(%rsp), %rdi
callq 0x2c570
movq 0x78(%rsp), %rcx
movq %rax, %rdx
xorl %eax, %eax
cmpq %rdx, %rcx
movb %al, 0x97(%rsp)
jne 0x2b568
movq 0x498(%rsp), %rdi
callq 0x2c5c0
movq %rax, 0x70(%rsp)
movq 0x488(%rsp), %rdi
callq 0x2c5c0
movq %rax, %rcx
movq 0x70(%rsp), %rax
cmpq %rcx, %rax
sete %al
movb %al, 0x97(%rsp)
movb 0x97(%rsp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x2b57a
jmp 0x2b60b
leaq 0x61a30(%rip), %rsi     # 0x8cfb1
leaq 0x160(%rsp), %rdi
movq %rdi, 0x68(%rsp)
movl $0x27, %edx
movl $0x3, %ecx
callq 0x86270
movq 0x68(%rsp), %rdi
leaq 0x61ade(%rip), %rsi     # 0x8d087
callq 0x2c610
jmp 0x2b5b0
leaq 0x160(%rsp), %rdi
callq 0x86630
jmp 0x2b60b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f0(%rsp)
movl %eax, 0x2ec(%rsp)
leaq 0x2f8(%rsp), %rdi
callq 0x86630
jmp 0x2ba4f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f0(%rsp)
movl %eax, 0x2ec(%rsp)
leaq 0x160(%rsp), %rdi
callq 0x86630
jmp 0x2ba4f
movq 0x498(%rsp), %rdi
callq 0x2c570
movq %rax, 0x60(%rsp)
movq 0x498(%rsp), %rdi
callq 0x2c5c0
movq 0x98(%rsp), %rdi
movq 0x60(%rsp), %rsi
movq %rax, %rdx
callq 0x2ba60
testb $0x1, %al
jne 0x2b648
jmp 0x2ba3a
movq 0x498(%rsp), %rdi
callq 0x2c560
movq %rax, 0x150(%rsp)
movq 0x488(%rsp), %rdi
callq 0x2c560
movq %rax, 0x148(%rsp)
movq 0x150(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x2b010
movq $0x1, 0x120(%rsp)
movq 0x98(%rsp), %rcx
movq 0x120(%rsp), %rax
cmpq (%rcx), %rax
ja 0x2ba2d
leaq 0x15f(%rsp), %rdi
callq 0x2bce0
movq %rax, 0x58(%rsp)
jmp 0x2b6c0
movq 0x58(%rsp), %rax
movq %rax, 0x118(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x2b0b0
jmp 0x2b6dc
movq $0x0, 0x110(%rsp)
movq 0x110(%rsp), %rax
cmpq 0x150(%rsp), %rax
je 0x2b901
movq 0x498(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x110(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x2c690
movq %rax, 0x50(%rsp)
jmp 0x2b727
movq 0x50(%rsp), %rdx
movq 0x48(%rsp), %rsi
leaq 0xe8(%rsp), %rdi
callq 0x2c640
jmp 0x2b740
movq 0x98(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
callq 0x2bd00
jmp 0x2b757
leaq 0xe8(%rsp), %rdi
callq 0x30940
movq 0x490(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x110(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x2c690
movq %rax, 0x40(%rsp)
jmp 0x2b78d
movq 0x40(%rsp), %rdx
movq 0x38(%rsp), %rsi
leaq 0xc0(%rsp), %rdi
callq 0x2c640
jmp 0x2b7a6
movq 0x98(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x2bdb0
jmp 0x2b7bd
leaq 0xc0(%rsp), %rdi
callq 0x30940
movq 0x98(%rsp), %rcx
movq 0x110(%rsp), %rax
xorl %edx, %edx
divq 0x8(%rcx)
movq 0x98(%rsp), %rax
movq 0x8(%rax), %rax
subq $0x1, %rax
cmpq %rax, %rdx
je 0x2b812
movq 0x110(%rsp), %rax
movq 0x150(%rsp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jne 0x2b8a4
movq 0x98(%rsp), %rdi
movq 0x110(%rsp), %rax
movq 0x8(%rdi), %rcx
xorl %edx, %edx
divq %rcx
movq %rdx, %rsi
incq %rsi
movss 0x10(%rdi), %xmm0
callq 0x2bf70
jmp 0x2b83d
jmp 0x2b8a4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f0(%rsp)
movl %eax, 0x2ec(%rsp)
jmp 0x2ba42
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f0(%rsp)
movl %eax, 0x2ec(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0x30940
jmp 0x2ba42
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x2f0(%rsp)
movl %eax, 0x2ec(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x30940
jmp 0x2ba42
movq 0x110(%rsp), %rax
movl $0x64, %ecx
xorl %edx, %edx
divq %rcx
cmpq $0x0, %rdx
jne 0x2b8e6
movq 0x120(%rsp), %rsi
movq 0x110(%rsp), %rdx
movq 0x150(%rsp), %rcx
leaq 0x6185d(%rip), %rdi     # 0x8d138
xorl %eax, %eax
callq 0x9060
jmp 0x2b8e4
jmp 0x2b8e6
jmp 0x2b8e8
movq 0x110(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x110(%rsp)
jmp 0x2b6e8
movq 0x120(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x118(%rsp), %rax
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rsi
leaq 0x15e(%rsp), %rdi
callq 0x2c000
movq %rax, 0x30(%rsp)
jmp 0x2b93a
movq 0x30(%rsp), %rdx
movq 0x28(%rsp), %rsi
leaq 0x6180d(%rip), %rdi     # 0x8d158
xorl %eax, %eax
callq 0x9060
jmp 0x2b954
leaq 0x15f(%rsp), %rdi
callq 0x2bce0
movq %rax, 0x20(%rsp)
jmp 0x2b968
movq 0x20(%rsp), %rax
movq %rax, 0xb0(%rsp)
cmpq $0x0, 0x148(%rsp)
jbe 0x2ba12
movq 0x98(%rsp), %rdi
movq 0x120(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x488(%rsp), %rsi
movq 0x480(%rsp), %rdx
callq 0x2c040
movq %rax, 0x18(%rsp)
jmp 0x2b9b5
movq 0x148(%rsp), %rax
movq %rax, (%rsp)
movq 0xb0(%rsp), %rax
movq %rax, 0xa8(%rsp)
movq 0xa8(%rsp), %rsi
leaq 0x15e(%rsp), %rdi
callq 0x2c000
movq %rax, 0x8(%rsp)
jmp 0x2b9ed
movq 0x8(%rsp), %r8
movq (%rsp), %rcx
movq 0x18(%rsp), %rdx
movq 0x10(%rsp), %rsi
leaq 0x61777(%rip), %rdi     # 0x8d17e
xorl %eax, %eax
callq 0x9060
jmp 0x2ba10
jmp 0x2ba12
jmp 0x2ba14
movq 0x120(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x120(%rsp)
jmp 0x2b693
leaq 0x128(%rsp), %rdi
callq 0x2c6c0
addq $0x4a8, %rsp            # imm = 0x4A8
retq
leaq 0x128(%rsp), %rdi
callq 0x2c6c0
movq 0x2f0(%rsp), %rdi
callq 0x95d0
nopl (%rax)