// File: /workspace/github_c_makefile_star2_O3/waynebhayes[P]SAHap/src/Genome.cpp
// Function: SAHap::Genome::optimize(bool)
void Genome::optimize(bool debug) {
	// unsigned int TARGET_MEC = 0;//this->haplotypes[0].size() * this->totalCoverage() * READ_ERROR_RATE;
	// Reset state
	this->t = this->tInitial;
	ResetBuffers();

	unsigned WINDOW_SIZE = increments * 2;
	double ERROR = READ_ERROR_RATE;
	double add = 0.0001; // FIXME: WTF is this?
	range.end = WINDOW_SIZE;
	
	for (auto& haplotype : this->haplotypes) {
		haplotype.initializeWindow(WINDOW_SIZE, increments);
	}

	// Target MEC for the Window
	double PTARGET_MEC = windowTotalCoverage() * ERROR;

	auto start_time = duration_cast<seconds>(system_clock::now().time_since_epoch());
	// assert(this->haplotypes.size() == 2); // FIXME need to change a few things below that assume only 0 and 1 exist.
	assert(this->haplotypes[0].size() == this->haplotypes[1].size());
	printf("Performing %ld meta-iterations of %d each using schedule %s,\n",
	    (long)(this->maxIterations/META_ITER), META_ITER, schedName[SCHEDULE]);
	printf("optimizing objective %s across %lu sites with total coverage %g, target MEC %g\n",
	    objName[OBJECTIVE], this->haplotypes[0].size(), this->meanCoverage(), PTARGET_MEC);

	
	int cpuSeconds = 0;
	int tmp = 0;
	
	while (range.start + WINDOW_SIZE <= numberOfSites) {
		this->t = this->getTemperature(this->curIteration);
		this->iteration();
		this->curIteration++;
		double pBad = this->pBad.getAverage();
		iteration_t prev = curIteration;
		DynamicSchedule(pBad, PTARGET_MEC);
		if (debug && curIteration % REPORT_INTERVAL == 0) {
			auto now_time = duration_cast<seconds>(system_clock::now().time_since_epoch());
			cpuSeconds = (int)(now_time - start_time).count();
			Report(cpuSeconds);
			// if(fracTime() > 0.5 && pBad < 0.01 && mec() <= TARGET_MEC) {
			//     printf("Exiting early because MEC %lu reached target\n", mec());
			//     this->curIteration = this->maxIterations; // basically done
			// }
		}
		if (this->done()){//} || (pmec() <= PTARGET_MEC)){
			range.start += increments;
			range.end += increments;
			curIteration = 0;
			tmp = cpuSeconds;
			
			for (auto& haplotype : haplotypes) {
				haplotype.incrementWindow();
			}

			add = 0;
			PTARGET_MEC = windowTotalCoverage() * ERROR;
		} else if (prev > curIteration) {
			add += 0.0005; // FIXME: WTF is this magic number?
			PTARGET_MEC = windowTotalCoverage() * (ERROR + add);
		}

		if (cpuSeconds  > tmp + 50){ // For Debugging to break out if program can't find optimal solution
			break;
		}
	}
	Report(cpuSeconds, true);
	printf("Finished optimizing %d sites using %s cost function\n", (int)this->haplotypes[0].size(), objName[OBJECTIVE]);
	cout << "MEC: " << mec() << endl;

	// for (auto h : haplotypes) {
	// 	// h.printCoverages();
	// 	h.print_mec();
	// }
	createBlocks();
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movl %esi, %ebp
movq %rdi, %rbx
movsd 0x3bc8(%rdi), %xmm0
movsd %xmm0, 0x3bc0(%rdi)
leaq 0x408(%rdi), %r14
movl $0x0, 0x400(%rdi)
movl $0x3fc, %edx            # imm = 0x3FC
xorl %esi, %esi
callq 0x2140
movl $0x1f60, %edx           # imm = 0x1F60
movq %r14, %rdi
xorl %esi, %esi
callq 0x2140
movl 0x3c00(%rbx), %r14d
addl %r14d, %r14d
movq %r14, 0x3bf0(%rbx)
movq 0x2368(%rbx), %r15
movq 0x2370(%rbx), %r12
cmpq %r12, %r15
je 0x3a2d
movl 0x3c00(%rbx), %edx
movq %r15, %rdi
movl %r14d, %esi
callq 0x70f6
addq $0xf8, %r15
jmp 0x3a0e
movq %rbx, %rdi
callq 0x31b2
movsd %xmm0, 0x8(%rsp)
callq 0x2050
movabsq $-0x112e0be826d694b3, %rcx # imm = 0xEED1F417D9296B4D
imulq %rcx
movq %rdx, %r15
movq 0x2368(%rbx), %rdi
callq 0x6eae
movq %rax, %r12
movl $0xf8, %edi
addq 0x2368(%rbx), %rdi
callq 0x6eae
cmpq %rax, %r12
jne 0x3df1
movq %r15, %rcx
shrq $0x3f, %rcx
sarq $0x1a, %r15
movsd 0x8(%rsp), %xmm0
mulsd 0x765e(%rip), %xmm0     # 0xb0f0
movsd %xmm0, 0x8(%rsp)
movabsq $0x346dc5d63886594b, %rax # imm = 0x346DC5D63886594B
mulq 0x3bd8(%rbx)
addq %rcx, %r15
movq %r15, 0x18(%rsp)
shrq $0xb, %rdx
movq 0xc7cc(%rip), %rcx      # 0x10288
leaq 0x784a(%rip), %rdi      # 0xb30d
xorl %r15d, %r15d
movq %rdx, %rsi
movl $0x2710, %edx           # imm = 0x2710
xorl %eax, %eax
callq 0x2040
movq 0xc78c(%rip), %r12      # 0x10268
movq 0x2368(%rbx), %rdi
callq 0x6eae
movq %rax, %r13
movq %rbx, %rdi
callq 0x3128
leaq 0x7851(%rip), %rdi      # 0xb34b
movq %r12, %rsi
movq %r13, %rdx
movq 0x8(%rsp), %xmm1
movb $0x2, %al
callq 0x2040
movsd 0x75e3(%rip), %xmm0     # 0xb0f8
movsd %xmm0, 0x10(%rsp)
xorl %r12d, %r12d
movq 0x3be8(%rbx), %rax
addq %r14, %rax
cmpq 0x3bf8(%rbx), %rax
ja 0x3d53
movsd 0x3be0(%rbx), %xmm0
movsd 0x74db(%rip), %xmm2     # 0xb020
unpcklps %xmm2, %xmm0            # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
movapd 0x74e0(%rip), %xmm3     # 0xb030
subpd %xmm3, %xmm0
movapd %xmm0, %xmm1
unpckhpd %xmm0, %xmm1            # xmm1 = xmm1[1],xmm0[1]
addsd %xmm0, %xmm1
movsd 0x3bd8(%rbx), %xmm0
unpcklps %xmm2, %xmm0            # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
subpd %xmm3, %xmm0
movapd %xmm0, %xmm2
unpckhpd %xmm0, %xmm2            # xmm2 = xmm2[1],xmm0[1]
addsd %xmm0, %xmm2
divsd %xmm2, %xmm1
movsd 0x3bc8(%rbx), %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x3bd0(%rbx), %xmm0
xorpd 0x74a3(%rip), %xmm0     # 0xb040
mulsd %xmm1, %xmm0
callq 0x2460
mulsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x3bc0(%rbx)
movq %rbx, %rdi
callq 0x364c
movq 0x3be0(%rbx), %r13
incq %r13
movq %r13, 0x3be0(%rbx)
movq 0x2348(%rbx), %rax
movsd 0x7524(%rip), %xmm0     # 0xb100
testq %rax, %rax
je 0x3c0e
movsd 0x2358(%rbx), %xmm0
movq %rax, %xmm1
punpckldq 0x742a(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0x7432(%rip), %xmm1     # 0xb030
movapd %xmm1, %xmm2
unpckhpd %xmm1, %xmm2            # xmm2 = xmm2[1],xmm1[1]
addsd %xmm1, %xmm2
divsd %xmm2, %xmm0
movq %rbx, %rdi
movq 0x8(%rsp), %xmm1
callq 0x3e54
movq 0x3be0(%rbx), %rcx
movq %rcx, %rax
shrq $0x3, %rax
movabsq $0x20c49ba5e353f7cf, %rdx # imm = 0x20C49BA5E353F7CF
mulq %rdx
testb %bpl, %bpl
je 0x3c8b
shrq $0x4, %rdx
imulq $0x3e8, %rdx, %rax      # imm = 0x3E8
movq %rcx, %rdx
subq %rax, %rdx
jne 0x3c8b
callq 0x2050
movabsq $0x112e0be826d694b3, %rcx # imm = 0x112E0BE826D694B3
imulq %rcx
movq %rdx, %r12
movq %rdx, %rax
shrq $0x3f, %rax
shrq $0x1a, %r12
addl %eax, %r12d
addl 0x18(%rsp), %r12d
movq %rbx, %rdi
movl %r12d, %esi
xorl %edx, %edx
callq 0x430a
movq 0x3be0(%rbx), %rcx
cmpq 0x3bd8(%rbx), %rcx
jae 0x3cd3
cmpq %rcx, %r13
jbe 0x3d46
movsd 0x10(%rsp), %xmm0
addsd 0x745d(%rip), %xmm0     # 0xb108
movsd %xmm0, 0x10(%rsp)
movq %rbx, %rdi
callq 0x31b2
movsd 0x10(%rsp), %xmm1
addsd 0x7429(%rip), %xmm1     # 0xb0f0
mulsd %xmm0, %xmm1
movsd %xmm1, 0x8(%rsp)
jmp 0x3d46
movdqu 0x3c00(%rbx), %xmm0
movdqu 0x3be8(%rbx), %xmm1
pshufd $0x44, %xmm0, %xmm0     # xmm0 = xmm0[0,1,0,1]
paddq %xmm1, %xmm0
movdqu %xmm0, 0x3be8(%rbx)
movq $0x0, 0x3be0(%rbx)
movq 0x2368(%rbx), %r13
movq 0x2370(%rbx), %r15
cmpq %r15, %r13
je 0x3d23
movq %r13, %rdi
callq 0x714c
addq $0xf8, %r13
jmp 0x3d0d
movq %rbx, %rdi
callq 0x31b2
mulsd 0x73bd(%rip), %xmm0     # 0xb0f0
movsd %xmm0, 0x8(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movl %r12d, %r15d
leal 0x32(%r15), %eax
cmpl %eax, %r12d
jle 0x3b1e
movq %rbx, %rdi
movl %r12d, %esi
movl $0x1, %edx
callq 0x430a
movq 0x2368(%rbx), %rdi
callq 0x6eae
movq 0xc4f2(%rip), %rdx      # 0x10268
leaq 0x761e(%rip), %rdi      # 0xb39b
movl %eax, %esi
xorl %eax, %eax
callq 0x2040
movq 0xc23b(%rip), %r14      # 0xffc8
leaq 0x763c(%rip), %rsi      # 0xb3d0
movl $0x5, %edx
movq %r14, %rdi
callq 0x22b0
movq %rbx, %rdi
callq 0x2f36
movq %r14, %rdi
callq 0x23d0
movq %rax, %r14
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r14, %rdi
movl $0xa, %esi
callq 0x2250
movsbl %al, %esi
movq %r14, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x21a0
movq %rbx, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x46b2
leaq 0x74b9(%rip), %rdi      # 0xb2b1
leaq 0x73f4(%rip), %rsi      # 0xb1f3
leaq 0x74e4(%rip), %rcx      # 0xb2ea
movl $0x160, %edx            # imm = 0x160
callq 0x2180