// File: /workspace/github_cpp_makefile_star2_O1/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 0x26b6c
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 0x235cf
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 0x27178
movq %r12, %rdi
callq 0x27e2c
movq %rax, %r12
leaq 0xa0(%rsp), %rdi
callq 0xd874
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 0x26dc2
movl $0x1, %ecx
leaq 0xd8(%rsp), %r12
movq %r12, %rdi
movq 0x200(%rsp), %rsi
movq %r14, %rdx
callq 0x27178
movq %r12, %rdi
callq 0x27e2c
movq %rax, %r12
leaq 0x60(%rsp), %rdi
callq 0xd874
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 0x26dc2
movq %r12, %rdi
movq (%rsp), %rsi
leaq 0x88(%rsp), %rdx
leaq 0x48(%rsp), %rcx
callq 0x3dac4
movq 0x220(%rsp), %rdi
movq %r12, %rsi
callq 0x2ed0c
movq %r12, %rdi
callq 0x26dc2
movq %r12, %rdi
callq 0x26b6c
movq (%rsp), %rdi
movq %r12, %rsi
leaq 0x48(%rsp), %rdx
callq 0x3e16e
leaq 0x20(%rsp), %r12
movq %r12, %rdi
movq 0x70(%rsp), %rsi
callq 0x27e5c
leaq 0x178(%rsp), %r13
movq %r13, %rdi
movq (%rsp), %rsi
movq %r12, %rdx
leaq 0x88(%rsp), %rcx
callq 0x3d76a
movq %r14, 0x18(%rsp)
leaq 0xb0(%rsp), %rdi
movq %r13, %rsi
leaq 0xd8(%rsp), %rdx
callq 0x2f830
movq %r13, %r14
movq %r13, %rdi
callq 0x26dc2
leaq 0x20(%rsp), %rdi
callq 0x26dc2
movq 0x8(%rsp), %rax
cmpq $0x0, 0x8(%rax)
je 0x23588
movq 0x10(%rsp), %r12
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x26b6c
testq %r12, %r12
je 0x23327
leaq -0x1(%r12), %rdx
movl $0x1, %ecx
movq 0x200(%rsp), %rdi
movq %r14, %rsi
callq 0x271c4
jmp 0x2334d
movl $0x0, 0x20(%rsp)
movq 0x200(%rsp), %rax
movq 0x8(%rax), %rdx
movl $0x1, %ecx
movq %r14, %rdi
leaq 0x20(%rsp), %rsi
callq 0x27d04
movq %r14, %rdi
callq 0x27e2c
leaq 0x20(%rsp), %r14
movq %r14, %rdi
movq (%rsp), %rsi
leaq 0xb0(%rsp), %rdx
movq %rax, %rcx
callq 0x3dac4
movq 0x218(%rsp), %rdi
movq %r14, %rsi
callq 0x2ed0c
movq %r14, %rdi
callq 0x26dc2
movl $0x1, %ecx
leaq 0x150(%rsp), %r14
movq %r14, %rdi
movq 0x80(%rsp), %rsi
movq %r12, %rdx
callq 0x27178
movq %r14, %rdi
callq 0x27e2c
movq %rax, %rbp
leaq 0x38(%rsp), %rdi
callq 0xd874
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 0x26dc2
leaq 0x128(%rsp), %rbx
movq %rbx, %rdi
movq (%rsp), %rsi
movq 0x210(%rsp), %rdx
leaq 0x20(%rsp), %r15
movq %r15, %rcx
callq 0x3d76a
movq %rbp, %rdi
movq %rbx, %rsi
leaq 0xb0(%rsp), %rdx
callq 0x2e952
movq %rbx, %rdi
callq 0x26dc2
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x37fda
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 0x276e2
leaq 0x128(%rsp), %r15
movq %r15, %rdi
movq %rbx, %rsi
leaq 0x150(%rsp), %rdx
callq 0x2e952
movq 0x210(%rsp), %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x27856
movq %r15, %rdi
callq 0x26dc2
leaq 0x100(%rsp), %rdi
callq 0x26dc2
testq %r12, %r12
je 0x2354d
movq (%rsp), %rdi
movq %r14, %rsi
movq %r14, %rdx
callq 0x3e16e
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
callq 0x27e5c
movq %rbx, %rdi
leaq 0xb0(%rsp), %rsi
callq 0x37a7e
leaq 0x128(%rsp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
movq %r14, %rdx
callq 0x2f830
leaq 0xb0(%rsp), %rdi
movq %rbx, %rsi
callq 0x2e81e
movq %rbx, %rdi
callq 0x26dc2
leaq 0x100(%rsp), %rdi
callq 0x26dc2
leaq 0x150(%rsp), %rdi
callq 0x26dc2
leaq 0x20(%rsp), %rdi
callq 0x26dc2
movq %r14, %rdi
callq 0x26dc2
cmpq 0x18(%rsp), %r13
jae 0x23588
incq %r13
decq %r12
movq 0x8(%rsp), %rax
cmpq 0x8(%rax), %r13
jb 0x232fe
leaq 0xb0(%rsp), %rdi
callq 0x26dc2
leaq 0xd8(%rsp), %rdi
callq 0x26dc2
leaq 0x48(%rsp), %r12
movq %r12, %rdi
callq 0x26dc2
leaq 0x88(%rsp), %rdi
callq 0x26dc2
decq 0x10(%rsp)
movq 0x18(%rsp), %r14
testq %r14, %r14
jne 0x23106
leaq 0x1a0(%rsp), %rdi
callq 0x26dc2
addq $0x1c8, %rsp            # imm = 0x1C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2360f
movq %rax, %rbx
jmp 0x23605
movq %rax, %rbx
leaq 0x178(%rsp), %rdi
callq 0x26dc2
leaq 0x20(%rsp), %rdi
jmp 0x236de
movq %rax, %rbx
jmp 0x23707
movq %rax, %rbx
jmp 0x236fa
jmp 0x23623
jmp 0x2362d
movq %rax, %rbx
jmp 0x236f0
jmp 0x2362d
movq %rax, %rbx
jmp 0x236e3
movq %rax, %rbx
leaq 0xd8(%rsp), %rdi
jmp 0x236f5
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
jmp 0x23702
jmp 0x236b4
jmp 0x236b4
jmp 0x2366d
jmp 0x2369d
jmp 0x2369d
jmp 0x2367f
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
jmp 0x236a8
jmp 0x236b4
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
callq 0x26dc2
jmp 0x2368e
movq %rax, %rbx
jmp 0x236ad
jmp 0x2368b
movq %rax, %rbx
jmp 0x236d6
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x26dc2
jmp 0x236a0
movq %rax, %rbx
leaq 0x150(%rsp), %rdi
callq 0x26dc2
leaq 0x20(%rsp), %rdi
jmp 0x236c4
movq %rax, %rbx
jmp 0x236c9
movq %rax, %rbx
leaq 0x150(%rsp), %rdi
callq 0x26dc2
leaq 0x178(%rsp), %rdi
callq 0x26dc2
leaq 0xb0(%rsp), %rdi
callq 0x26dc2
leaq 0xd8(%rsp), %rdi
callq 0x26dc2
leaq 0x48(%rsp), %rdi
callq 0x26dc2
leaq 0x88(%rsp), %rdi
callq 0x26dc2
leaq 0x1a0(%rsp), %rdi
callq 0x26dc2
movq %rbx, %rdi
callq 0xa780