// File: btbujiangjun[P]abcdl/src/rnn/RNN.cpp
// Function: abcdl::rnn::RNN::train(abcdl::algebra::MatrixSet<float> const&, abcdl::algebra::MatrixSet<float> const&)
void RNN::train(const abcdl::algebra::MatSet& train_seq_data,
                const abcdl::algebra::MatSet& train_seq_label){
	if(!check_data(train_seq_data, train_seq_label)){
        printf("RNN::sgd Data dim Error.\n");
		return ;
	}
	
	size_t num_train_data = train_seq_data.size();
    abcdl::utils::Shuffler shuffler(num_train_data);
	auto now = []{return std::chrono::system_clock::now();};

	abcdl::algebra::Mat state;
	abcdl::algebra::Mat activation;
	
	abcdl::algebra::Mat batch_derivate_weight(_U.rows(), _U.cols());
	abcdl::algebra::Mat batch_derivate_pre_weight(_W.rows(), _W.cols());
	abcdl::algebra::Mat batch_derivate_act_weight(_V.rows(), _V.cols());

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

		for(size_t j = 0; j != num_train_data; j++){
			_layer->farward(train_seq_data[shuffler.get(j)], _U, _W, _V, state, activation);
			_layer->backward(train_seq_data[shuffler.get(j)], train_seq_label[shuffler.get(j)], _U, _W, _V, state, activation, batch_derivate_weight, batch_derivate_pre_weight, batch_derivate_act_weight);

            if( j % _mini_batch_size == (_mini_batch_size - 1) || j == (num_train_data - 1)){
				size_t n = j % _mini_batch_size + 1;
    			_U -= batch_derivate_weight * (_alpha / n);
			    _W -= batch_derivate_pre_weight * (_alpha / n);
			    _V -= batch_derivate_act_weight * (_alpha / n);

			}

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

        if(_path != ""){
            write_model(_path);
        }

        printf("Epoch[%ld] training run time: %lld ms, loss[%f] base loss[%f]\n", i, (long long int)std::chrono::duration_cast<std::chrono::milliseconds>(now() - start_time).count(), loss(train_seq_data, train_seq_label), std::log(_feature_dim));
	}

	printf("training finished.\n");
}

// Assembly:
subq $0x378, %rsp            # imm = 0x378
movq %rdi, 0x370(%rsp)
movq %rsi, 0x368(%rsp)
movq %rdx, 0x360(%rsp)
movq 0x370(%rsp), %rdi
movq %rdi, 0x110(%rsp)
movq 0x368(%rsp), %rsi
movq 0x360(%rsp), %rdx
callq 0x54e60
testb $0x1, %al
jne 0x543cb
leaq 0x638fa(%rip), %rdi     # 0xb7cb9
movb $0x0, %al
callq 0xb080
jmp 0x54dee
movq 0x368(%rsp), %rdi
callq 0x193c0
movq %rax, 0x358(%rsp)
movq 0x358(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x541a0
leaq 0x308(%rsp), %rdi
callq 0x5b7d0
jmp 0x54404
leaq 0x2d0(%rsp), %rdi
callq 0x5b7d0
jmp 0x54413
movq 0x110(%rsp), %rdi
addq $0x70, %rdi
callq 0x531e0
movq %rax, 0x108(%rsp)
jmp 0x5442e
movq 0x110(%rsp), %rdi
addq $0x70, %rdi
callq 0x531f0
movq %rax, 0x100(%rsp)
jmp 0x54449
movq 0x100(%rsp), %rdx
movq 0x108(%rsp), %rsi
leaq 0x2a8(%rsp), %rdi
callq 0x5b810
jmp 0x54468
movq 0x110(%rsp), %rdi
addq $0xa8, %rdi
callq 0x531e0
movq %rax, 0xf8(%rsp)
jmp 0x54486
movq 0x110(%rsp), %rdi
addq $0xa8, %rdi
callq 0x531f0
movq %rax, 0xf0(%rsp)
jmp 0x544a4
movq 0xf0(%rsp), %rdx
movq 0xf8(%rsp), %rsi
leaq 0x280(%rsp), %rdi
callq 0x5b810
jmp 0x544c3
movq 0x110(%rsp), %rdi
addq $0xe0, %rdi
callq 0x531e0
movq %rax, 0xe8(%rsp)
jmp 0x544e1
movq 0x110(%rsp), %rdi
addq $0xe0, %rdi
callq 0x531f0
movq %rax, 0xe0(%rsp)
jmp 0x544ff
movq 0xe0(%rsp), %rdx
movq 0xe8(%rsp), %rsi
leaq 0x258(%rsp), %rdi
callq 0x5b810
jmp 0x5451e
movq $0x0, 0x250(%rsp)
movq 0x110(%rsp), %rcx
movq 0x250(%rsp), %rax
cmpq 0x18(%rcx), %rax
je 0x54d90
leaq 0x338(%rsp), %rdi
callq 0x54240
jmp 0x54553
leaq 0x337(%rsp), %rdi
callq 0x54f00
movq %rax, 0xd8(%rsp)
jmp 0x5456a
movq 0xd8(%rsp), %rax
movq %rax, 0x248(%rsp)
movq $0x0, 0x240(%rsp)
movq 0x240(%rsp), %rax
cmpq 0x358(%rsp), %rax
je 0x54c36
movq 0x110(%rsp), %rax
movq 0x118(%rax), %rax
movq %rax, 0xc0(%rsp)
movq 0x368(%rsp), %rax
movq %rax, 0xc8(%rsp)
movq 0x240(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x55bf0
movq %rax, 0xd0(%rsp)
jmp 0x545e2
movq 0xd0(%rsp), %rdx
movq 0xc8(%rsp), %rsi
leaq 0x218(%rsp), %rdi
callq 0x55ba0
jmp 0x54601
movq 0xc0(%rsp), %rdi
movq 0x110(%rsp), %r8
movq %r8, %rdx
addq $0x70, %rdx
movq %r8, %rcx
addq $0xa8, %rcx
addq $0xe0, %r8
movq %rsp, %rax
leaq 0x2d0(%rsp), %rsi
movq %rsi, (%rax)
leaq 0x218(%rsp), %rsi
leaq 0x308(%rsp), %r9
callq 0x53210
jmp 0x5464e
leaq 0x218(%rsp), %rdi
callq 0x5bc10
movq 0x110(%rsp), %rax
movq 0x118(%rax), %rax
movq %rax, 0xa8(%rsp)
movq 0x368(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0x240(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x55bf0
movq %rax, 0xb8(%rsp)
jmp 0x546a1
movq 0xb8(%rsp), %rdx
movq 0xb0(%rsp), %rsi
leaq 0x1f0(%rsp), %rdi
callq 0x55ba0
jmp 0x546c0
movq 0x360(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0x240(%rsp), %rsi
leaq 0x338(%rsp), %rdi
callq 0x55bf0
movq %rax, 0xa0(%rsp)
jmp 0x546ef
movq 0xa0(%rsp), %rdx
movq 0x98(%rsp), %rsi
leaq 0x1c8(%rsp), %rdi
callq 0x55ba0
jmp 0x5470e
movq 0xa8(%rsp), %rdi
movq 0x110(%rsp), %r9
movq %r9, %rcx
addq $0x70, %rcx
movq %r9, %r8
addq $0xa8, %r8
addq $0xe0, %r9
movq %rsp, %rax
leaq 0x258(%rsp), %rdx
movq %rdx, 0x20(%rax)
leaq 0x280(%rsp), %rdx
movq %rdx, 0x18(%rax)
leaq 0x2a8(%rsp), %rdx
movq %rdx, 0x10(%rax)
leaq 0x2d0(%rsp), %rdx
movq %rdx, 0x8(%rax)
leaq 0x308(%rsp), %rdx
movq %rdx, (%rax)
leaq 0x1f0(%rsp), %rsi
leaq 0x1c8(%rsp), %rdx
callq 0x53800
jmp 0x5478b
leaq 0x1c8(%rsp), %rdi
callq 0x5bc10
leaq 0x1f0(%rsp), %rdi
callq 0x5bc10
movq 0x110(%rsp), %rcx
movq 0x240(%rsp), %rax
xorl %edx, %edx
divq 0x20(%rcx)
movq 0x110(%rsp), %rax
movq 0x20(%rax), %rax
subq $0x1, %rax
cmpq %rax, %rdx
je 0x547ed
movq 0x240(%rsp), %rax
movq 0x358(%rsp), %rcx
subq $0x1, %rcx
cmpq %rcx, %rax
jne 0x54bd9
movq 0x110(%rsp), %rcx
movq 0x240(%rsp), %rax
movq 0x20(%rcx), %rcx
xorl %edx, %edx
divq %rcx
movq 0x110(%rsp), %rax
incq %rdx
movq %rdx, 0x1c0(%rsp)
movss 0x28(%rax), %xmm0
movss %xmm0, 0x8c(%rsp)
movq 0x1c0(%rsp), %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, 0x90(%rsp)
testq %rax, %rax
movss %xmm0, 0x94(%rsp)
js 0x54874
movss 0x90(%rsp), %xmm0
movss %xmm0, 0x94(%rsp)
movss 0x8c(%rsp), %xmm0
movss 0x94(%rsp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, 0x194(%rsp)
leaq 0x198(%rsp), %rdi
leaq 0x2a8(%rsp), %rsi
leaq 0x194(%rsp), %rdx
callq 0x6b950
jmp 0x548b2
movq 0x110(%rsp), %rdi
addq $0x70, %rdi
leaq 0x198(%rsp), %rsi
callq 0x6b580
jmp 0x548cd
leaq 0x198(%rsp), %rdi
callq 0x5bc10
movq 0x110(%rsp), %rax
movss 0x28(%rax), %xmm0
movss %xmm0, 0x80(%rsp)
movq 0x1c0(%rsp), %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, 0x84(%rsp)
testq %rax, %rax
movss %xmm0, 0x88(%rsp)
js 0x5493d
movss 0x84(%rsp), %xmm0
movss %xmm0, 0x88(%rsp)
movss 0x80(%rsp), %xmm0
movss 0x88(%rsp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, 0x164(%rsp)
leaq 0x168(%rsp), %rdi
leaq 0x280(%rsp), %rsi
leaq 0x164(%rsp), %rdx
callq 0x6b950
jmp 0x5497b
movq 0x110(%rsp), %rdi
addq $0xa8, %rdi
leaq 0x168(%rsp), %rsi
callq 0x6b580
jmp 0x54999
leaq 0x168(%rsp), %rdi
callq 0x5bc10
movq 0x110(%rsp), %rax
movss 0x28(%rax), %xmm0
movss %xmm0, 0x74(%rsp)
movq 0x1c0(%rsp), %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, 0x78(%rsp)
testq %rax, %rax
movss %xmm0, 0x7c(%rsp)
js 0x549fa
movss 0x78(%rsp), %xmm0
movss %xmm0, 0x7c(%rsp)
movss 0x74(%rsp), %xmm0
movss 0x7c(%rsp), %xmm1
divss %xmm1, %xmm0
movss %xmm0, 0x134(%rsp)
leaq 0x138(%rsp), %rdi
leaq 0x258(%rsp), %rsi
leaq 0x134(%rsp), %rdx
callq 0x6b950
jmp 0x54a32
movq 0x110(%rsp), %rdi
addq $0xe0, %rdi
leaq 0x138(%rsp), %rsi
callq 0x6b580
jmp 0x54a50
leaq 0x138(%rsp), %rdi
callq 0x5bc10
jmp 0x54bd9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54e37
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54e2a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54e1d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54e10
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54e03
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54df6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
leaq 0x218(%rsp), %rdi
callq 0x5bc10
jmp 0x54df6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
jmp 0x54b55
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
leaq 0x1c8(%rsp), %rdi
callq 0x5bc10
leaq 0x1f0(%rsp), %rdi
callq 0x5bc10
jmp 0x54df6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
leaq 0x198(%rsp), %rdi
callq 0x5bc10
jmp 0x54df6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
leaq 0x168(%rsp), %rdi
callq 0x5bc10
jmp 0x54df6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x300(%rsp)
movl %eax, 0x2fc(%rsp)
leaq 0x138(%rsp), %rdi
callq 0x5bc10
jmp 0x54df6
movq 0x240(%rsp), %rax
movl $0x5, %ecx
xorl %edx, %edx
divq %rcx
cmpq $0x0, %rdx
jne 0x54c1b
movq 0x250(%rsp), %rsi
movq 0x240(%rsp), %rdx
movq 0x358(%rsp), %rcx
leaq 0x630c3(%rip), %rdi     # 0xb7cd3
xorl %eax, %eax
callq 0xb080
jmp 0x54c19
jmp 0x54c1b
jmp 0x54c1d
movq 0x240(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x240(%rsp)
jmp 0x54586
movq 0x110(%rsp), %rdi
addq $0x30, %rdi
leaq 0x60631(%rip), %rsi     # 0xb527a
callq 0x55c20
movb %al, 0x73(%rsp)
jmp 0x54c54
movb 0x73(%rsp), %al
testb $0x1, %al
jne 0x54c5e
jmp 0x54c76
movq 0x110(%rsp), %rdi
movq %rdi, %rsi
addq $0x30, %rsi
callq 0x54f20
jmp 0x54c74
jmp 0x54c76
movq 0x250(%rsp), %rax
movq %rax, 0x60(%rsp)
leaq 0x337(%rsp), %rdi
callq 0x54f00
movq %rax, 0x68(%rsp)
jmp 0x54c97
movq 0x68(%rsp), %rax
movq %rax, 0x118(%rsp)
leaq 0x118(%rsp), %rdi
leaq 0x248(%rsp), %rsi
callq 0x55c80
movq %rax, 0x58(%rsp)
jmp 0x54cc0
movq 0x58(%rsp), %rax
movq %rax, 0x120(%rsp)
leaq 0x120(%rsp), %rdi
callq 0x55c50
movq %rax, 0x50(%rsp)
jmp 0x54ce1
movq 0x50(%rsp), %rax
movq %rax, 0x128(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x55cd0
movq %rax, 0x48(%rsp)
jmp 0x54d02
movq 0x110(%rsp), %rdi
movq 0x368(%rsp), %rsi
movq 0x360(%rsp), %rdx
callq 0x55100
movss %xmm0, 0x44(%rsp)
jmp 0x54d27
movq 0x110(%rsp), %rax
movss 0x44(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0x30(%rsp)
movq (%rax), %rdi
callq 0x55ce0
movsd %xmm0, 0x38(%rsp)
jmp 0x54d4f
movsd 0x38(%rsp), %xmm1
movsd 0x30(%rsp), %xmm0
movq 0x48(%rsp), %rdx
movq 0x60(%rsp), %rsi
leaq 0x62f88(%rip), %rdi     # 0xb7cf4
movb $0x2, %al
callq 0xb080
jmp 0x54d75
jmp 0x54d77
movq 0x250(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x250(%rsp)
jmp 0x5452a
leaq 0x62f9c(%rip), %rdi     # 0xb7d33
xorl %eax, %eax
callq 0xb080
jmp 0x54da0
leaq 0x258(%rsp), %rdi
callq 0x5bc10
leaq 0x280(%rsp), %rdi
callq 0x5bc10
leaq 0x2a8(%rsp), %rdi
callq 0x5bc10
leaq 0x2d0(%rsp), %rdi
callq 0x5bc10
leaq 0x308(%rsp), %rdi
callq 0x5bc10
leaq 0x338(%rsp), %rdi
callq 0x55d20
addq $0x378, %rsp            # imm = 0x378
retq
leaq 0x258(%rsp), %rdi
callq 0x5bc10
leaq 0x280(%rsp), %rdi
callq 0x5bc10
leaq 0x2a8(%rsp), %rdi
callq 0x5bc10
leaq 0x2d0(%rsp), %rdi
callq 0x5bc10
leaq 0x308(%rsp), %rdi
callq 0x5bc10
leaq 0x338(%rsp), %rdi
callq 0x55d20
movq 0x300(%rsp), %rdi
callq 0xb980
nopw %cs:(%rax,%rax)