// File: KokiKishimoto[P]cp_decomposition/cp.cpp
// Function: CP::train(Data&, int, int, ModelFileWriter&)
void train(Data& data, int maxEpoch, int negativeSize, ModelFileWriter& mfw) {
		int sampleC = 1;
		double all = 0.0;
		double loss = 0.0;
		std::vector<Triple> train_triples = data.triples;
		std::set<long long> triple_key_set = data.triple_key_set;
		RandomSampler sampler(data.key_gen, data.entity_counter, data.relation_counter, rnd);

		for (int iter = 1; iter <= maxEpoch; ++iter) {
			std::shuffle(train_triples.begin(), train_triples.end(), rnd);
			std::cerr << "Epoch " << iter << ":" << std::endl;
			for (Triple& triple : train_triples) {
				if ((sampleC % 1000) == 0) {
					std::cerr << sampleC << " ";
					++all;
					updater.decay(all);
				}
				++sampleC;
				for (int i = 0; i <= negativeSize; i++) {
					if (i == 0) {
						loss += computeGradients(triple, 1.0);
						updater.SGD(triple, outVec1, outVec2, outVec3, norms, subjVec, objVec, relationVec);
					} else {
						Triple neg_triple = sampler.negativeSamplingSbj(triple, triple_key_set);
						loss += computeGradients(neg_triple, -1.0);
						updater.SGD(neg_triple, outVec1, outVec2, outVec3, norms, subjVec, objVec, relationVec);

						neg_triple = sampler.negativeSamplingObj(triple, triple_key_set);
						loss += computeGradients(neg_triple, -1.0);
						updater.SGD(neg_triple, outVec1, outVec2, outVec3, norms, subjVec, objVec, relationVec);
					}
				}
				if (updater.learningRate <= 0.0) {
					std::cerr << std::endl;
					std::cerr << "Learning rate was zero " << std::endl;
					std::cerr << "Total loss: " << loss << std::endl;
					mfw.save(subjVec, objVec, relationVec, op, data, iter);
				}
			}
			std::cerr << std::endl;
			std::cerr << std::fixed << std::setprecision(15) << "Total loss: " << loss << std::endl;

			loss = 0.0;
			sampleC = 1;

			if (iter % 10 == 0) {
				mfw.save(subjVec, objVec, relationVec, op, data, iter);
			}
		}
	}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %rbx
subq $0x1558, %rsp           # imm = 0x1558
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movl %ecx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x14c0(%rbp)
movl $0x1, -0x2c(%rbp)
movq $0x0, -0x38(%rbp)
movq $0x0, -0x40(%rbp)
movq -0x18(%rbp), %rsi
addq $0xf8, %rsi
leaq -0x58(%rbp), %rdi
callq 0xbbc0
movq -0x18(%rbp), %rsi
addq $0xc8, %rsi
leaq -0x88(%rbp), %rdi
callq 0xbcb0
jmp 0x483d
movq -0x14c0(%rbp), %r8
movq -0x18(%rbp), %rax
movq %rax, %rsi
addq $0x110, %rsi            # imm = 0x110
movl (%rax), %edx
movl 0x4(%rax), %ecx
addq $0x208, %r8             # imm = 0x208
leaq -0x1450(%rbp), %rdi
callq 0xbce0
jmp 0x486c
movl $0x1, -0x1454(%rbp)
movl -0x1454(%rbp), %eax
cmpl -0x1c(%rbp), %eax
jg 0x4ee7
leaq -0x58(%rbp), %rdi
movq %rdi, -0x14c8(%rbp)
callq 0x63f0
movq -0x14c8(%rbp), %rdi
movq %rax, -0x1460(%rbp)
callq 0x6420
movq -0x14c0(%rbp), %rdx
movq %rax, -0x1468(%rbp)
addq $0x208, %rdx            # imm = 0x208
movq -0x1460(%rbp), %rdi
movq -0x1468(%rbp), %rsi
callq 0xbda0
jmp 0x48d2
movq 0x13717(%rip), %rdi     # 0x17ff0
leaq 0xb801(%rip), %rsi      # 0x100e1
callq 0x3280
movq %rax, -0x14d0(%rbp)
jmp 0x48ee
movq -0x14d0(%rbp), %rdi
movl -0x1454(%rbp), %esi
callq 0x3430
movq %rax, -0x14d8(%rbp)
jmp 0x4909
movq -0x14d8(%rbp), %rdi
leaq 0xb7d1(%rip), %rsi      # 0x100e8
callq 0x3280
movq %rax, -0x14e0(%rbp)
jmp 0x4925
movq -0x14e0(%rbp), %rdi
movq 0x13685(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x493a
leaq -0x58(%rbp), %rax
movq %rax, -0x1470(%rbp)
movq -0x1470(%rbp), %rdi
callq 0x63f0
movq %rax, -0x1478(%rbp)
movq -0x1470(%rbp), %rdi
callq 0x6420
movq %rax, -0x1480(%rbp)
leaq -0x1478(%rbp), %rdi
leaq -0x1480(%rbp), %rsi
callq 0x6450
testb $0x1, %al
jne 0x4987
jmp 0x4dc0
leaq -0x1478(%rbp), %rdi
callq 0x6490
movq %rax, -0x1488(%rbp)
movl -0x2c(%rbp), %eax
movl $0x3e8, %ecx            # imm = 0x3E8
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x4a44
movl -0x2c(%rbp), %esi
movq 0x13638(%rip), %rdi     # 0x17ff0
callq 0x3430
movq %rax, -0x14e8(%rbp)
jmp 0x49c6
movq -0x14e8(%rbp), %rdi
leaq 0xb739(%rip), %rsi      # 0x1010d
callq 0x3280
jmp 0x49db
movq -0x14c0(%rbp), %rdi
movsd -0x38(%rbp), %xmm0
movsd 0xb621(%rip), %xmm1     # 0x10010
addsd %xmm1, %xmm0
movsd %xmm0, -0x38(%rbp)
addq $0x8, %rdi
movsd -0x38(%rbp), %xmm0
callq 0xc010
jmp 0x4a08
jmp 0x4a44
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x90(%rbp)
movl %eax, -0x94(%rbp)
jmp 0x4f06
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x90(%rbp)
movl %eax, -0x94(%rbp)
leaq -0x88(%rbp), %rdi
callq 0x52a0
jmp 0x4f06
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movl $0x0, -0x148c(%rbp)
movl -0x148c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jg 0x4ccd
cmpl $0x0, -0x148c(%rbp)
jne 0x4b17
movq -0x14c0(%rbp), %rdi
movq -0x1488(%rbp), %rsi
movsd 0xb587(%rip), %xmm0     # 0x10010
callq 0xc050
movsd %xmm0, -0x14f0(%rbp)
jmp 0x4a98
movq -0x14c0(%rbp), %rbx
movsd -0x14f0(%rbp), %xmm1
movsd -0x40(%rbp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x40(%rbp)
movq %rbx, %rdi
addq $0x8, %rdi
movq -0x1488(%rbp), %rsi
movq %rbx, %rdx
addq $0x190, %rdx            # imm = 0x190
movq %rbx, %rcx
addq $0x1a8, %rcx            # imm = 0x1A8
movq %rbx, %r8
addq $0x1c0, %r8             # imm = 0x1C0
movq %rbx, %r9
addq $0x1d8, %r9             # imm = 0x1D8
movq %rbx, %r10
addq $0x30, %r10
movq %rbx, %r11
addq $0x48, %r11
addq $0x60, %rbx
movq %rsp, %rax
movq %rbx, 0x10(%rax)
movq %r11, 0x8(%rax)
movq %r10, (%rax)
callq 0xc3b0
jmp 0x4b12
jmp 0x4cb7
movq -0x1488(%rbp), %rdx
leaq -0x14a0(%rbp), %rdi
leaq -0x1450(%rbp), %rsi
leaq -0x88(%rbp), %rcx
callq 0xc940
jmp 0x4b3a
movq -0x14c0(%rbp), %rdi
leaq -0x14a0(%rbp), %rsi
movsd 0xb4c8(%rip), %xmm0     # 0x10018
callq 0xc050
movsd %xmm0, -0x14f8(%rbp)
jmp 0x4b5f
movq -0x14c0(%rbp), %r11
movsd -0x14f8(%rbp), %xmm1
movsd -0x40(%rbp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x40(%rbp)
movq %r11, %rdi
addq $0x8, %rdi
movq %r11, %rdx
addq $0x190, %rdx            # imm = 0x190
movq %r11, %rcx
addq $0x1a8, %rcx            # imm = 0x1A8
movq %r11, %r8
addq $0x1c0, %r8             # imm = 0x1C0
movq %r11, %r9
addq $0x1d8, %r9             # imm = 0x1D8
movq %r11, %rsi
addq $0x30, %rsi
movq %r11, %r10
addq $0x48, %r10
addq $0x60, %r11
movq %rsp, %rax
movq %r11, 0x10(%rax)
movq %r10, 0x8(%rax)
movq %rsi, (%rax)
leaq -0x14a0(%rbp), %rsi
callq 0xc3b0
jmp 0x4bd9
movq -0x1488(%rbp), %rdx
leaq -0x14b4(%rbp), %rdi
leaq -0x1450(%rbp), %rsi
leaq -0x88(%rbp), %rcx
callq 0xca30
jmp 0x4bfc
movq -0x14c0(%rbp), %rdi
movb -0x14a4(%rbp), %al
movb %al, -0x1490(%rbp)
movups -0x14b4(%rbp), %xmm0
movaps %xmm0, -0x14a0(%rbp)
leaq -0x14a0(%rbp), %rsi
movsd 0xb3ec(%rip), %xmm0     # 0x10018
callq 0xc050
movsd %xmm0, -0x1500(%rbp)
jmp 0x4c3b
movq -0x14c0(%rbp), %r11
movsd -0x1500(%rbp), %xmm1
movsd -0x40(%rbp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x40(%rbp)
movq %r11, %rdi
addq $0x8, %rdi
movq %r11, %rdx
addq $0x190, %rdx            # imm = 0x190
movq %r11, %rcx
addq $0x1a8, %rcx            # imm = 0x1A8
movq %r11, %r8
addq $0x1c0, %r8             # imm = 0x1C0
movq %r11, %r9
addq $0x1d8, %r9             # imm = 0x1D8
movq %r11, %rsi
addq $0x30, %rsi
movq %r11, %r10
addq $0x48, %r10
addq $0x60, %r11
movq %rsp, %rax
movq %r11, 0x10(%rax)
movq %r10, 0x8(%rax)
movq %rsi, (%rax)
leaq -0x14a0(%rbp), %rsi
callq 0xc3b0
jmp 0x4cb5
jmp 0x4cb7
jmp 0x4cb9
movl -0x148c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x148c(%rbp)
jmp 0x4a57
movq -0x14c0(%rbp), %rax
xorps %xmm0, %xmm0
ucomisd 0x10(%rax), %xmm0
jb 0x4dad
movq 0x13307(%rip), %rdi     # 0x17ff0
movq 0x132c8(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x4cf7
movq 0x132f2(%rip), %rdi     # 0x17ff0
leaq 0xb3e5(%rip), %rsi      # 0x100ea
callq 0x3280
movq %rax, -0x1508(%rbp)
jmp 0x4d13
movq -0x1508(%rbp), %rdi
movq 0x13297(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x4d28
movq 0x132c1(%rip), %rdi     # 0x17ff0
leaq 0xb3cc(%rip), %rsi      # 0x10102
callq 0x3280
movq %rax, -0x1510(%rbp)
jmp 0x4d44
movq -0x1510(%rbp), %rdi
movsd -0x40(%rbp), %xmm0
callq 0x3480
movq %rax, -0x1518(%rbp)
jmp 0x4d5e
movq -0x1518(%rbp), %rdi
movq 0x1324c(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x4d73
movq -0x14c0(%rbp), %r8
movq -0x28(%rbp), %rdi
movq %r8, %rsi
addq $0x30, %rsi
movq %r8, %rdx
addq $0x48, %rdx
movq %r8, %rcx
addq $0x60, %rcx
movq -0x18(%rbp), %r9
movl -0x1454(%rbp), %r10d
movq %rsp, %rax
movl %r10d, (%rax)
callq 0xcb20
jmp 0x4dab
jmp 0x4dad
jmp 0x4daf
leaq -0x1478(%rbp), %rdi
callq 0x6540
jmp 0x496b
movq 0x13229(%rip), %rdi     # 0x17ff0
movq 0x131ea(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x4dd5
movq 0x13214(%rip), %rdi     # 0x17ff0
leaq 0x863d(%rip), %rsi      # 0xd420
callq 0x30e0
movq %rax, -0x1520(%rbp)
jmp 0x4df1
movl $0xf, %edi
callq 0xd450
movl %eax, -0x1524(%rbp)
jmp 0x4e03
movq -0x1520(%rbp), %rdi
movl -0x1524(%rbp), %eax
movl %eax, -0x14b8(%rbp)
movl -0x14b8(%rbp), %esi
callq 0x33f0
movq %rax, -0x1530(%rbp)
jmp 0x4e2a
movq -0x1530(%rbp), %rdi
leaq 0xb2ca(%rip), %rsi      # 0x10102
callq 0x3280
movq %rax, -0x1538(%rbp)
jmp 0x4e46
movq -0x1538(%rbp), %rdi
movsd -0x40(%rbp), %xmm0
callq 0x3480
movq %rax, -0x1540(%rbp)
jmp 0x4e60
movq -0x1540(%rbp), %rdi
movq 0x1314a(%rip), %rsi     # 0x17fb8
callq 0x32c0
jmp 0x4e75
xorps %xmm0, %xmm0
movsd %xmm0, -0x40(%rbp)
movl $0x1, -0x2c(%rbp)
movl -0x1454(%rbp), %eax
movl $0xa, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x4ed1
movq -0x14c0(%rbp), %r8
movq -0x28(%rbp), %rdi
movq %r8, %rsi
addq $0x30, %rsi
movq %r8, %rdx
addq $0x48, %rdx
movq %r8, %rcx
addq $0x60, %rcx
movq -0x18(%rbp), %r9
movl -0x1454(%rbp), %r10d
movq %rsp, %rax
movl %r10d, (%rax)
callq 0xcb20
jmp 0x4ecf
jmp 0x4ed1
jmp 0x4ed3
movl -0x1454(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1454(%rbp)
jmp 0x4876
leaq -0x88(%rbp), %rdi
callq 0x52a0
leaq -0x58(%rbp), %rdi
callq 0x5240
addq $0x1558, %rsp           # imm = 0x1558
popq %rbx
popq %rbp
retq
leaq -0x58(%rbp), %rdi
callq 0x5240
movq -0x90(%rbp), %rdi
callq 0x3440
nopl (%rax,%rax)