// File: /workspace/github_cpp_makefile_star2_O3/btbujiangjun[P]abcdl/src/rnn/Layer.cpp
// Function: abcdl::rnn::Layer::backward(abcdl::algebra::Matrix<float> const&, abcdl::algebra::Matrix<float> const&, abcdl::algebra::Matrix<float>&, abcdl::algebra::Matrix<float>&, abcdl::algebra::Matrix<float>&, abcdl::algebra::Matrix<float> const&, abcdl::algebra::Matrix<float> const&, abcdl::algebra::Matrix<float>&, abcdl::algebra::Matrix<float>&, abcdl::algebra::Matrix<float>&)
void Layer::backward(const abcdl::algebra::Mat& train_seq_data,
					 const abcdl::algebra::Mat& train_seq_label,
					 abcdl::algebra::Mat& weight,
					 abcdl::algebra::Mat& pre_weight,
					 abcdl::algebra::Mat& act_weight,
					 const abcdl::algebra::Mat& state,
					 const abcdl::algebra::Mat& activation,
					 abcdl::algebra::Mat& derivate_weight,
					 abcdl::algebra::Mat& derivate_pre_weight,
					 abcdl::algebra::Mat& derivate_act_weight){
	abcdl::algebra::Mat derivate_output;
	_cost->delta(derivate_output, activation, train_seq_label);
	
	size_t seq_size = train_seq_data.rows();
	for(size_t s = seq_size; s != 0 ; s--){
		size_t t = s - 1;
		auto derivate_output_t = derivate_output.get_row(t).transpose();
		auto state_t = state.get_row(t).transpose();

        //update derivate_act_weight
		derivate_act_weight += helper.outer(derivate_output_t, state_t);

        //calc derivate_t
		abcdl::algebra::Mat state_derivate;
		helper.sigmoid_derivative(state_derivate, state_t);
		auto derivate_t = helper.dot(act_weight.Ts(), derivate_output_t) * state_derivate;

		//back_propagation steps
		for(size_t step = 0; step < _bptt_truncate && step <= t; step++){
			size_t bptt_step = t - step;
			abcdl::algebra::Mat derivate_state_t;
			if(bptt_step > 0){
				state.get_row(&derivate_state_t, bptt_step - 1);
			}else{
				derivate_state_t.reset(0, state.cols(), 1);
			}

            //update derivate_pre_weight
			derivate_pre_weight += helper.outer(derivate_t, derivate_state_t.transpose());
			
            //update derivate_weight
			auto train_data_t = train_seq_data.get_row(bptt_step).transpose();
            auto derivate_weight_t = helper.dot(derivate_weight, train_data_t) + derivate_t;

            size_t idx = train_data_t.argmax(0, abcdl::algebra::Axis_type::ROW);
            derivate_weight.set_col(idx, derivate_weight.get_col(idx) + derivate_weight_t);

			//update delta
			if(bptt_step > 0){
				helper.sigmoid_derivative(derivate_state_t, derivate_state_t);
				derivate_t = pre_weight.Ts().dot(derivate_t) * derivate_state_t;
			}
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1c8, %rsp            # imm = 0x1C8
movq %r9, 0x70(%rsp)
movq %r8, 0x78(%rsp)
movq %rdx, %rbx
movq %rsi, %r12
movq %rdi, %r13
movq 0x208(%rsp), %r14
leaq 0x1a0(%rsp), %r15
movq %r15, %rdi
callq 0x267d8
movq %r13, 0x8(%rsp)
movq 0x10(%r13), %rdi
movq (%rdi), %rax
movq %r15, %rsi
movq %r14, %rdx
movq %rbx, %rcx
callq *0x10(%rax)
movq (%r12), %r14
testq %r14, %r14
movq %r12, 0x80(%rsp)
je 0x23247
movq 0x8(%rsp), %rax
addq $0x20, %rax
movq %rax, (%rsp)
leaq -0x1(%r14), %rax
movq %rax, 0x10(%rsp)
leaq 0x48(%rsp), %r12
decq %r14
movl $0x1, %ecx
movq %r12, %rdi
leaq 0x1a0(%rsp), %rsi
movq %r14, %rdx
callq 0x26de4
movq %r12, %rdi
callq 0x27a96
movq %rax, %r12
leaq 0xa0(%rsp), %rdi
callq 0xd788
movq (%r12), %rax
movq %rax, 0x88(%rsp)
movq 0x8(%r12), %rcx
movq %rcx, 0x90(%rsp)
imulq %rax, %rcx
leaq (,%rcx,4), %rbp
movabsq $0x3fffffffffffffff, %rax # imm = 0x3FFFFFFFFFFFFFFF
cmpq %rax, %rcx
movq %rbp, %rdi
movq $-0x1, %rax
cmovaq %rax, %rdi
callq 0xa030
movq %rax, 0x98(%rsp)
movq 0x10(%r12), %rsi
movq %rax, %rdi
movq %rbp, %rdx
callq 0xa3a0
leaq 0x48(%rsp), %rdi
callq 0x26a2e
movl $0x1, %ecx
leaq 0xd8(%rsp), %r12
movq %r12, %rdi
movq 0x200(%rsp), %rsi
movq %r14, %rdx
callq 0x26de4
movq %r12, %rdi
callq 0x27a96
movq %rax, %r12
leaq 0x60(%rsp), %rdi
callq 0xd788
movq (%r12), %rax
movq %rax, 0x48(%rsp)
movq 0x8(%r12), %rcx
movq %rcx, 0x50(%rsp)
imulq %rax, %rcx
leaq (,%rcx,4), %rbp
movabsq $0x3fffffffffffffff, %rax # imm = 0x3FFFFFFFFFFFFFFF
cmpq %rax, %rcx
movq %rbp, %rdi
movq $-0x1, %rax
cmovaq %rax, %rdi
callq 0xa030
movq %rax, 0x58(%rsp)
movq 0x10(%r12), %rsi
movq %rax, %rdi
movq %rbp, %rdx
callq 0xa3a0
leaq 0xd8(%rsp), %r12
movq %r12, %rdi
callq 0x26a2e
movq %r12, %rdi
movq (%rsp), %rsi
leaq 0x88(%rsp), %rdx
leaq 0x48(%rsp), %rcx
callq 0x3d79c
movq 0x220(%rsp), %rdi
movq %r12, %rsi
callq 0x2e920
movq %r12, %rdi
callq 0x26a2e
movq %r12, %rdi
callq 0x267d8
movq (%rsp), %rdi
movq %r12, %rsi
leaq 0x48(%rsp), %rdx
callq 0x3de56
leaq 0x20(%rsp), %r12
movq %r12, %rdi
movq 0x70(%rsp), %rsi
callq 0x27ac6
leaq 0x178(%rsp), %r13
movq %r13, %rdi
movq (%rsp), %rsi
movq %r12, %rdx
leaq 0x88(%rsp), %rcx
callq 0x3d460
movq %r14, 0x18(%rsp)
leaq 0xb0(%rsp), %rdi
movq %r13, %rsi
leaq 0xd8(%rsp), %rdx
callq 0x2f47a
movq %r13, %r14
movq %r13, %rdi
callq 0x26a2e
leaq 0x20(%rsp), %rdi
callq 0x26a2e
movq 0x8(%rsp), %rax
cmpq $0x0, 0x8(%rax)
je 0x23200
movq 0x10(%rsp), %r12
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x267d8
testq %r12, %r12
je 0x22f9f
leaq -0x1(%r12), %rdx
movl $0x1, %ecx
movq 0x200(%rsp), %rdi
movq %r14, %rsi
callq 0x26e30
jmp 0x22fc5
movl $0x0, 0x20(%rsp)
movq 0x200(%rsp), %rax
movq 0x8(%rax), %rdx
movl $0x1, %ecx
movq %r14, %rdi
leaq 0x20(%rsp), %rsi
callq 0x2796e
movq %r14, %rdi
callq 0x27a96
leaq 0x20(%rsp), %r14
movq %r14, %rdi
movq (%rsp), %rsi
leaq 0xb0(%rsp), %rdx
movq %rax, %rcx
callq 0x3d79c
movq 0x218(%rsp), %rdi
movq %r14, %rsi
callq 0x2e920
movq %r14, %rdi
callq 0x26a2e
movl $0x1, %ecx
leaq 0x150(%rsp), %r14
movq %r14, %rdi
movq 0x80(%rsp), %rsi
movq %r12, %rdx
callq 0x26de4
movq %r14, %rdi
callq 0x27a96
movq %rax, %rbp
leaq 0x38(%rsp), %rdi
callq 0xd788
movq (%rbp), %rax
movq %rax, 0x20(%rsp)
movq 0x8(%rbp), %rcx
movq %rcx, 0x28(%rsp)
imulq %rax, %rcx
leaq (,%rcx,4), %r15
movabsq $0x3fffffffffffffff, %rax # imm = 0x3FFFFFFFFFFFFFFF
cmpq %rax, %rcx
movq %r15, %rdi
movq $-0x1, %rax
cmovaq %rax, %rdi
callq 0xa030
movq %rax, 0x30(%rsp)
movq 0x10(%rbp), %rsi
movq %rax, %rdi
movq %r15, %rdx
callq 0xa3a0
leaq 0x150(%rsp), %rbp
movq %rbp, %rdi
callq 0x26a2e
leaq 0x128(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %rsi
movq 0x210(%rsp), %rdx
leaq 0x20(%rsp), %r15
movq %r15, %rcx
callq 0x3d460
movq %rbp, %rdi
movq %rbx, %rsi
leaq 0xb0(%rsp), %rdx
callq 0x2e560
movq %rbx, %rdi
callq 0x26a2e
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x37d44
leaq 0x178(%rsp), %r14
movq %rax, %rbp
movl $0x1, %ecx
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
movq 0x210(%rsp), %rsi
movq %rax, %rdx
callq 0x2735c
leaq 0x128(%rsp), %r15
movq %r15, %rdi
movq %rbx, %rsi
leaq 0x150(%rsp), %rdx
callq 0x2e560
movq 0x210(%rsp), %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x274d0
movq %r15, %rdi
callq 0x26a2e
leaq 0x100(%rsp), %rdi
callq 0x26a2e
testq %r12, %r12
je 0x231c5
movq (%rsp), %rdi
movq %r14, %rsi
movq %r14, %rdx
callq 0x3de56
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
callq 0x27ac6
movq %rbx, %rdi
leaq 0xb0(%rsp), %rsi
callq 0x377e8
leaq 0x128(%rsp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x2f47a
leaq 0xb0(%rsp), %rdi
movq %rbx, %rsi
callq 0x2e41a
movq %rbx, %rdi
callq 0x26a2e
leaq 0x100(%rsp), %rdi
callq 0x26a2e
leaq 0x150(%rsp), %rdi
callq 0x26a2e
leaq 0x20(%rsp), %rdi
callq 0x26a2e
movq %r14, %rdi
callq 0x26a2e
cmpq 0x18(%rsp), %r13
jae 0x23200
incq %r13
decq %r12
movq 0x8(%rsp), %rax
cmpq 0x8(%rax), %r13
jb 0x22f76
leaq 0xb0(%rsp), %rdi
callq 0x26a2e
leaq 0xd8(%rsp), %rdi
callq 0x26a2e
leaq 0x48(%rsp), %r12
movq %r12, %rdi
callq 0x26a2e
leaq 0x88(%rsp), %rdi
callq 0x26a2e
decq 0x10(%rsp)
movq 0x18(%rsp), %r14
testq %r14, %r14
jne 0x22d7e
leaq 0x1a0(%rsp), %rdi
callq 0x26a2e
addq $0x1c8, %rsp            # imm = 0x1C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x23287
movq %rax, %rbx
jmp 0x2327d
movq %rax, %rbx
leaq 0x178(%rsp), %rdi
callq 0x26a2e
leaq 0x20(%rsp), %rdi
jmp 0x23356
movq %rax, %rbx
jmp 0x2337f
movq %rax, %rbx
jmp 0x23372
jmp 0x2329b
jmp 0x232a5
movq %rax, %rbx
jmp 0x23368
jmp 0x232a5
movq %rax, %rbx
jmp 0x2335b
movq %rax, %rbx
leaq 0xd8(%rsp), %rdi
jmp 0x2336d
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
jmp 0x2337a
jmp 0x2332c
jmp 0x2332c
jmp 0x232e5
jmp 0x23315
jmp 0x23315
jmp 0x232f7
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
jmp 0x23320
jmp 0x2332c
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
callq 0x26a2e
jmp 0x23306
movq %rax, %rbx
jmp 0x23325
jmp 0x23303
movq %rax, %rbx
jmp 0x2334e
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x26a2e
jmp 0x23318
movq %rax, %rbx
leaq 0x150(%rsp), %rdi
callq 0x26a2e
leaq 0x20(%rsp), %rdi
jmp 0x2333c
movq %rax, %rbx
jmp 0x23341
movq %rax, %rbx
leaq 0x150(%rsp), %rdi
callq 0x26a2e
leaq 0x178(%rsp), %rdi
callq 0x26a2e
leaq 0xb0(%rsp), %rdi
callq 0x26a2e
leaq 0xd8(%rsp), %rdi
callq 0x26a2e
leaq 0x48(%rsp), %rdi
callq 0x26a2e
leaq 0x88(%rsp), %rdi
callq 0x26a2e
leaq 0x1a0(%rsp), %rdi
callq 0x26a2e
movq %rbx, %rdi
callq 0xa780