// File: 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:
subq $0x418, %rsp            # imm = 0x418
movq 0x440(%rsp), %rax
movq 0x438(%rsp), %rax
movq 0x430(%rsp), %rax
movq 0x428(%rsp), %rax
movq 0x420(%rsp), %rax
movq %rdi, 0x410(%rsp)
movq %rsi, 0x408(%rsp)
movq %rdx, 0x400(%rsp)
movq %rcx, 0x3f8(%rsp)
movq %r8, 0x3f0(%rsp)
movq %r9, 0x3e8(%rsp)
movq 0x410(%rsp), %rax
movq %rax, 0x70(%rsp)
leaq 0x3c0(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x5b7d0
movq 0x70(%rsp), %rax
movq 0x78(%rsp), %rsi
movq 0x10(%rax), %rdi
movq 0x428(%rsp), %rdx
movq 0x400(%rsp), %rcx
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
jmp 0x538a7
movq 0x408(%rsp), %rdi
callq 0x531e0
movq %rax, 0x68(%rsp)
jmp 0x538bb
movq 0x68(%rsp), %rax
movq %rax, 0x3a8(%rsp)
movq 0x3a8(%rsp), %rax
movq %rax, 0x3a0(%rsp)
cmpq $0x0, 0x3a0(%rsp)
je 0x54171
movq 0x3a0(%rsp), %rax
decq %rax
movq %rax, 0x398(%rsp)
movq 0x398(%rsp), %rdx
leaq 0x348(%rsp), %rdi
leaq 0x3c0(%rsp), %rsi
movl $0x1, %ecx
callq 0x5bf50
jmp 0x5391e
leaq 0x348(%rsp), %rdi
callq 0x5d370
movq %rax, 0x60(%rsp)
jmp 0x53932
movq 0x60(%rsp), %rsi
leaq 0x370(%rsp), %rdi
callq 0x19300
jmp 0x53946
leaq 0x348(%rsp), %rdi
callq 0x5bc10
movq 0x420(%rsp), %rsi
movq 0x398(%rsp), %rdx
leaq 0x2f8(%rsp), %rdi
movl $0x1, %ecx
callq 0x5bf50
jmp 0x53977
leaq 0x2f8(%rsp), %rdi
callq 0x5d370
movq %rax, 0x58(%rsp)
jmp 0x5398b
movq 0x58(%rsp), %rsi
leaq 0x320(%rsp), %rdi
callq 0x19300
jmp 0x5399f
leaq 0x2f8(%rsp), %rdi
callq 0x5bc10
movq 0x70(%rsp), %rsi
addq $0x20, %rsi
leaq 0x2d0(%rsp), %rdi
leaq 0x370(%rsp), %rdx
leaq 0x320(%rsp), %rcx
callq 0x91fa0
jmp 0x539d4
movq 0x440(%rsp), %rdi
leaq 0x2d0(%rsp), %rsi
callq 0x6a9b0
jmp 0x539eb
leaq 0x2d0(%rsp), %rdi
callq 0x5bc10
leaq 0x2a8(%rsp), %rdi
callq 0x5b7d0
jmp 0x53a07
movq 0x70(%rsp), %rdi
addq $0x20, %rdi
leaq 0x2a8(%rsp), %rsi
leaq 0x320(%rsp), %rdx
callq 0x92fc0
jmp 0x53a27
movq 0x70(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x50(%rsp)
movq 0x3e8(%rsp), %rsi
leaq 0x230(%rsp), %rdi
callq 0x5d3b0
jmp 0x53a4c
movq 0x50(%rsp), %rsi
leaq 0x258(%rsp), %rdi
leaq 0x230(%rsp), %rdx
leaq 0x370(%rsp), %rcx
callq 0x919b0
jmp 0x53a70
leaq 0x280(%rsp), %rdi
leaq 0x258(%rsp), %rsi
leaq 0x2a8(%rsp), %rdx
callq 0x6baf0
jmp 0x53a8f
leaq 0x258(%rsp), %rdi
callq 0x5bc10
leaq 0x230(%rsp), %rdi
callq 0x5bc10
movq $0x0, 0x228(%rsp)
movq 0x70(%rsp), %rdx
movq 0x228(%rsp), %rcx
xorl %eax, %eax
cmpq 0x8(%rdx), %rcx
movb %al, 0x4f(%rsp)
jae 0x53ae5
movq 0x228(%rsp), %rax
cmpq 0x398(%rsp), %rax
setbe %al
movb %al, 0x4f(%rsp)
movb 0x4f(%rsp), %al
testb $0x1, %al
jne 0x53af2
jmp 0x540ee
movq 0x398(%rsp), %rax
movq 0x228(%rsp), %rcx
subq %rcx, %rax
movq %rax, 0x220(%rsp)
leaq 0x1f8(%rsp), %rdi
callq 0x5b7d0
jmp 0x53b1c
cmpq $0x0, 0x220(%rsp)
jbe 0x53ca8
movq 0x420(%rsp), %rdi
movq 0x220(%rsp), %rdx
decq %rdx
leaq 0x1f8(%rsp), %rsi
movl $0x1, %ecx
callq 0x5bff0
jmp 0x53b52
jmp 0x53cea
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x54186
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x348(%rsp), %rdi
callq 0x5bc10
jmp 0x54186
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x54162
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x2f8(%rsp), %rdi
callq 0x5bc10
jmp 0x54162
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x54155
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x2d0(%rsp), %rdi
callq 0x5bc10
jmp 0x54155
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x54148
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x53c64
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x258(%rsp), %rdi
callq 0x5bc10
leaq 0x230(%rsp), %rdi
callq 0x5bc10
jmp 0x54148
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x5413b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x540df
movl $0x0, 0x1f4(%rsp)
movq 0x420(%rsp), %rdi
callq 0x531f0
movq %rax, 0x40(%rsp)
jmp 0x53cc7
movq 0x40(%rsp), %rdx
leaq 0x1f8(%rsp), %rdi
leaq 0x1f4(%rsp), %rsi
movl $0x1, %ecx
callq 0x5d120
jmp 0x53ce8
jmp 0x53cea
movq 0x70(%rsp), %rax
addq $0x20, %rax
movq %rax, 0x30(%rsp)
leaq 0x1f8(%rsp), %rdi
callq 0x5d370
movq %rax, 0x38(%rsp)
jmp 0x53d0c
movq 0x38(%rsp), %rcx
movq 0x30(%rsp), %rsi
leaq 0x1c8(%rsp), %rdi
leaq 0x280(%rsp), %rdx
callq 0x91fa0
jmp 0x53d2d
movq 0x438(%rsp), %rdi
leaq 0x1c8(%rsp), %rsi
callq 0x6a9b0
jmp 0x53d44
leaq 0x1c8(%rsp), %rdi
callq 0x5bc10
movq 0x408(%rsp), %rsi
movq 0x220(%rsp), %rdx
leaq 0x178(%rsp), %rdi
movl $0x1, %ecx
callq 0x5bf50
jmp 0x53d75
leaq 0x178(%rsp), %rdi
callq 0x5d370
movq %rax, 0x28(%rsp)
jmp 0x53d89
movq 0x28(%rsp), %rsi
leaq 0x1a0(%rsp), %rdi
callq 0x19300
jmp 0x53d9d
leaq 0x178(%rsp), %rdi
callq 0x5bc10
movq 0x70(%rsp), %rsi
addq $0x20, %rsi
movq 0x430(%rsp), %rdx
leaq 0x128(%rsp), %rdi
leaq 0x1a0(%rsp), %rcx
callq 0x919b0
jmp 0x53dd2
leaq 0x150(%rsp), %rdi
leaq 0x128(%rsp), %rsi
leaq 0x280(%rsp), %rdx
callq 0x6a360
jmp 0x53df1
leaq 0x128(%rsp), %rdi
callq 0x5bc10
xorl %edx, %edx
movl %edx, %esi
leaq 0x1a0(%rsp), %rdi
callq 0x85020
movq %rax, 0x20(%rsp)
jmp 0x53e16
movq 0x20(%rsp), %rax
movq %rax, 0x120(%rsp)
movq 0x430(%rsp), %rsi
movq %rsi, 0x10(%rsp)
movq 0x120(%rsp), %rdx
movq %rdx, 0x18(%rsp)
leaq 0xd0(%rsp), %rdi
movl $0x1, %ecx
callq 0x5c830
jmp 0x53e51
leaq 0xf8(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
leaq 0x150(%rsp), %rdx
callq 0x6a360
jmp 0x53e70
movq 0x18(%rsp), %rsi
movq 0x10(%rsp), %rdi
leaq 0xf8(%rsp), %rdx
callq 0x5caa0
jmp 0x53e89
leaq 0xf8(%rsp), %rdi
callq 0x5bc10
leaq 0xd0(%rsp), %rdi
callq 0x5bc10
cmpq $0x0, 0x220(%rsp)
jbe 0x54085
movq 0x70(%rsp), %rdi
addq $0x20, %rdi
leaq 0x1f8(%rsp), %rdx
movq %rdx, %rsi
callq 0x92fc0
jmp 0x53ecd
movq 0x3f0(%rsp), %rsi
leaq 0x80(%rsp), %rdi
callq 0x5d3b0
jmp 0x53ee4
leaq 0x80(%rsp), %rdi
leaq 0x280(%rsp), %rsi
callq 0x84680
movq %rax, 0x8(%rsp)
jmp 0x53f00
movq 0x8(%rsp), %rsi
leaq 0xa8(%rsp), %rdi
leaq 0x1f8(%rsp), %rdx
callq 0x6baf0
jmp 0x53f1c
leaq 0x280(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x6a0a0
jmp 0x53f33
leaq 0xa8(%rsp), %rdi
callq 0x5bc10
leaq 0x80(%rsp), %rdi
callq 0x5bc10
jmp 0x54085
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x1c8(%rsp), %rdi
callq 0x5bc10
jmp 0x540df
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x178(%rsp), %rdi
callq 0x5bc10
jmp 0x540df
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x540d2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x5bc10
jmp 0x540d2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x540c5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x5402d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0xf8(%rsp), %rdi
callq 0x5bc10
leaq 0xd0(%rsp), %rdi
callq 0x5bc10
jmp 0x540c5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
jmp 0x54076
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3b8(%rsp)
movl %eax, 0x3b4(%rsp)
leaq 0xa8(%rsp), %rdi
callq 0x5bc10
leaq 0x80(%rsp), %rdi
callq 0x5bc10
jmp 0x540c5
leaq 0x150(%rsp), %rdi
callq 0x5bc10
leaq 0x1a0(%rsp), %rdi
callq 0x5bc10
leaq 0x1f8(%rsp), %rdi
callq 0x5bc10
movq 0x228(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x228(%rsp)
jmp 0x53ab5
leaq 0x150(%rsp), %rdi
callq 0x5bc10
leaq 0x1a0(%rsp), %rdi
callq 0x5bc10
leaq 0x1f8(%rsp), %rdi
callq 0x5bc10
jmp 0x5413b
leaq 0x280(%rsp), %rdi
callq 0x5bc10
leaq 0x2a8(%rsp), %rdi
callq 0x5bc10
leaq 0x320(%rsp), %rdi
callq 0x5bc10
leaq 0x370(%rsp), %rdi
callq 0x5bc10
movq 0x3a0(%rsp), %rax
addq $-0x1, %rax
movq %rax, 0x3a0(%rsp)
jmp 0x538d8
leaq 0x280(%rsp), %rdi
callq 0x5bc10
leaq 0x2a8(%rsp), %rdi
callq 0x5bc10
leaq 0x320(%rsp), %rdi
callq 0x5bc10
leaq 0x370(%rsp), %rdi
callq 0x5bc10
jmp 0x54186
leaq 0x3c0(%rsp), %rdi
callq 0x5bc10
addq $0x418, %rsp            # imm = 0x418
retq
leaq 0x3c0(%rsp), %rdi
callq 0x5bc10
movq 0x3b8(%rsp), %rdi
callq 0xb980