// File: /workspace/github_cpp_makefile_star2_O2/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, 0x18(%rsp)
movq %r8, 0x20(%rsp)
movq %rdx, %rbx
movq %rsi, %r12
movq %rdi, %r13
movq 0x208(%rsp), %r14
leaq 0x1a0(%rsp), %r15
movq %r15, %rdi
callq 0x23808
movq 0x10(%r13), %rdi
movq (%rdi), %rax
movq %r15, %rsi
movq %r14, %rdx
movq %rbx, %rcx
callq *0x10(%rax)
movq %r12, 0x28(%rsp)
movq (%r12), %rbx
movq %r13, 0x30(%rsp)
leaq 0x20(%r13), %rax
movq %rax, (%rsp)
leaq -0x1(%rbx), %rax
movq %rax, 0x8(%rsp)
leaq 0x128(%rsp), %r15
leaq 0x178(%rsp), %r14
subq $0x1, %rbx
jb 0x208d9
leaq 0xb0(%rsp), %r12
movq %r12, %rdi
leaq 0x1a0(%rsp), %rsi
movq %rbx, %rdx
pushq $0x1
popq %rcx
callq 0x23bc0
movq %r12, %rdi
callq 0x24698
leaq 0x150(%rsp), %rdi
movq %rax, %rsi
callq 0x1175e
leaq 0xb0(%rsp), %rdi
callq 0x23a32
leaq 0x88(%rsp), %r12
movq %r12, %rdi
movq 0x200(%rsp), %rsi
movq %rbx, %rdx
pushq $0x1
popq %rcx
callq 0x23bc0
movq %r12, %rdi
callq 0x24698
leaq 0xb0(%rsp), %r12
movq %r12, %rdi
movq %rax, %rsi
callq 0x1175e
leaq 0x88(%rsp), %rbp
movq %rbp, %rdi
callq 0x23a32
movq %rbp, %rdi
movq (%rsp), %rsi
leaq 0x150(%rsp), %rdx
movq %r12, %rcx
callq 0x338e6
movq 0x220(%rsp), %rdi
movq %rbp, %rsi
callq 0x29a38
movq %rbp, %rdi
callq 0x23a32
movq %rbp, %rdi
callq 0x23808
movq (%rsp), %rdi
movq %rbp, %rsi
leaq 0xb0(%rsp), %rdx
callq 0x33e52
movq %r15, %rdi
movq 0x18(%rsp), %rsi
callq 0x246c8
leaq 0x38(%rsp), %r12
movq %r12, %rdi
movq (%rsp), %rsi
movq %r15, %rdx
leaq 0x150(%rsp), %rcx
callq 0x335c8
movq %rbx, 0x10(%rsp)
leaq 0x60(%rsp), %rdi
movq %r12, %rsi
leaq 0x88(%rsp), %rdx
callq 0x2a086
movq %r12, %rdi
callq 0x23a32
movq %r15, %rdi
callq 0x23a32
movq 0x8(%rsp), %rbp
xorl %r12d, %r12d
cmpq 0x10(%rsp), %r12
ja 0x20899
movq 0x30(%rsp), %rax
cmpq 0x8(%rax), %r12
jae 0x20899
leaq 0x38(%rsp), %rdi
callq 0x23808
testq %rbp, %rbp
je 0x206d3
leaq -0x1(%rbp), %rdx
movq 0x200(%rsp), %rdi
leaq 0x38(%rsp), %rbx
movq %rbx, %rsi
pushq $0x1
popq %rcx
callq 0x23c0c
jmp 0x206fc
andl $0x0, 0x128(%rsp)
movq 0x200(%rsp), %rax
movq 0x8(%rax), %rdx
leaq 0x38(%rsp), %rdi
movq %r15, %rsi
pushq $0x1
popq %rcx
callq 0x24598
leaq 0x38(%rsp), %rbx
movq %rbx, %rdi
callq 0x24698
movq %r15, %rdi
movq (%rsp), %rsi
leaq 0x60(%rsp), %rdx
movq %rax, %rcx
callq 0x338e6
movq 0x218(%rsp), %rdi
movq %r15, %rsi
callq 0x29a38
movq %r15, %rdi
callq 0x23a32
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
movq 0x28(%rsp), %rsi
movq %rbp, %rdx
pushq $0x1
popq %rcx
callq 0x23bc0
movq %rbx, %rdi
callq 0x24698
movq %r15, %rdi
movq %rax, %rsi
callq 0x1175e
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
callq 0x23a32
movq %r14, %rdi
movq (%rsp), %rsi
movq 0x210(%rsp), %rdx
movq %r15, %rcx
callq 0x335c8
movq %rbx, %rdi
movq %r14, %rsi
leaq 0x60(%rsp), %rdx
callq 0x29810
movq %r14, %rdi
callq 0x23a32
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2f89c
movq %rax, %rbx
leaq 0xd8(%rsp), %r13
movq %r13, %rdi
movq 0x210(%rsp), %rsi
movq %rax, %rdx
pushq $0x1
popq %rcx
callq 0x240a6
movq %r14, %rdi
movq %r13, %rsi
leaq 0x100(%rsp), %rdx
callq 0x29810
movq 0x210(%rsp), %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x2420a
movq %r14, %rdi
callq 0x23a32
leaq 0xd8(%rsp), %rdi
callq 0x23a32
testq %rbp, %rbp
je 0x2086f
movq (%rsp), %rdi
leaq 0x38(%rsp), %rdx
movq %rdx, %rsi
callq 0x33e52
leaq 0xd8(%rsp), %rbx
movq %rbx, %rdi
movq 0x20(%rsp), %rsi
callq 0x246c8
movq %rbx, %rdi
leaq 0x60(%rsp), %rsi
callq 0x2f396
movq %r14, %rdi
movq %rax, %rsi
leaq 0x38(%rsp), %rdx
callq 0x2a086
leaq 0x60(%rsp), %rdi
movq %r14, %rsi
callq 0x296f2
movq %r14, %rdi
callq 0x23a32
leaq 0xd8(%rsp), %rdi
callq 0x23a32
leaq 0x100(%rsp), %rdi
callq 0x23a32
movq %r15, %rdi
callq 0x23a32
leaq 0x38(%rsp), %rdi
callq 0x23a32
incq %r12
decq %rbp
jmp 0x2068c
leaq 0x60(%rsp), %rdi
callq 0x23a32
leaq 0x88(%rsp), %rdi
callq 0x23a32
leaq 0xb0(%rsp), %rdi
callq 0x23a32
leaq 0x150(%rsp), %rdi
callq 0x23a32
decq 0x8(%rsp)
movq 0x10(%rsp), %rbx
jmp 0x20550
leaq 0x1a0(%rsp), %rdi
callq 0x23a32
addq $0x1c8, %rsp            # imm = 0x1C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2090d
jmp 0x20915
movq %rax, %rbx
jmp 0x209fa
jmp 0x20937
jmp 0x20937
movq %rax, %rbx
jmp 0x2092a
movq %rax, %rbx
jmp 0x20a07
movq %rax, %rbx
jmp 0x209ed
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x23a32
leaq 0x128(%rsp), %rdi
jmp 0x209db
movq %rax, %rbx
jmp 0x209e0
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
jmp 0x20a02
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
jmp 0x209f5
jmp 0x209c9
jmp 0x209aa
jmp 0x209c9
jmp 0x20986
movq %rax, %rbx
jmp 0x209d6
jmp 0x20970
jmp 0x209c9
movq %rax, %rbx
jmp 0x209ba
jmp 0x20998
movq %rax, %rbx
leaq 0x178(%rsp), %rdi
jmp 0x209b5
jmp 0x209aa
movq %rax, %rbx
leaq 0x178(%rsp), %rdi
callq 0x23a32
jmp 0x2099b
movq %rax, %rbx
leaq 0xd8(%rsp), %rdi
callq 0x23a32
jmp 0x209ad
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
callq 0x23a32
leaq 0x128(%rsp), %rdi
callq 0x23a32
jmp 0x209cc
movq %rax, %rbx
leaq 0x38(%rsp), %rdi
callq 0x23a32
leaq 0x60(%rsp), %rdi
callq 0x23a32
leaq 0x88(%rsp), %rdi
callq 0x23a32
leaq 0xb0(%rsp), %rdi
callq 0x23a32
leaq 0x150(%rsp), %rdi
callq 0x23a32
leaq 0x1a0(%rsp), %rdi
callq 0x23a32
movq %rbx, %rdi
callq 0xa7a0
movq %rax, %rbx
leaq 0x100(%rsp), %rdi
jmp 0x209c2
nopl (%rax)