// File: /workspace/github_cpp_makefile_star2_O3/tonymugen[P]sampleSNPs/random.cpp
// Function: sampFiles::RanDraw::vitter(double const&, double const&)
volatile uint64_t RanDraw::vitter(const double &n, const double &N){
	// The notation follows Vitter's (1987) as closely as possible
	// Note that my runif() is on [0,1] (Vitter assumes (0,1)), so I have to sometimes adjust accordingly
	uint64_t S = 0;
	double alphaInv = 13.0;
	if (n >= N/alphaInv) { // if the threshold is not satisfied, use Vitter's A algorithm
		return this->vitterA(n, N);
	} else if (n == 1){ // trivial case
		do {
			S = static_cast<uint64_t>(floor(N * this->runif()));
			
		} while (S == static_cast<uint64_t>(N)); // s == N would be a problem because it would overshoot the end of the array/file (in base-0 space); effectively sampling [0,1) uniform to prevent this
		return S;

	}
	
	// if we pass all thresholds, we use Vitter's rejection scheme
	double nInv     = 1.0/n;
	double nMin1inv = 1.0/(n - 1.0);
	double qu1db    = 1.0 + N - n;
	uint64_t qu1    = static_cast<uint64_t>(qu1db);
	double Vprime;
	double X;
	double Sdb;
	double U;
	double y1;
	
	// outer loop in Vitter (1987) A2
	while (1) {
		
		unsigned int d2tst = 0;
		do {  // step D2; generate U and X
			Vprime = pow(this->runif(), nInv);
			X      = N * (1.0 - Vprime);
			S      = floor(X);
			d2tst++;
		} while (S >= qu1);
		
		U      = this->runif();
		Sdb    = static_cast<double>(S);
		y1     = pow(U*N/qu1db, nMin1inv);
		Vprime = y1 * (1.0 - X/N) * (qu1db/(qu1db - Sdb));
		if (Vprime < 1.0) { // Step D3: accept test 2.8 (Vitter 1987)
			break;
		}
		// moving on to Step D4
		double y2  = 1.0;
		double top = N - 1.0;
		double bottom;
		double limit;
		if (Sdb < n - 1.0) {
			bottom = N - n;
			limit  = N - Sdb;
		} else {
			bottom = N - Sdb - 1.0;
			limit  = qu1db;
		}
		
		// calculate f(|_X_|)
		for (double t = N - 1.0; t >= limit; t--) {
			y2 = y2 * top/bottom;
			top--;
			bottom--;
		}
		if (N/(N - X) >= y1 * pow(y2, nMin1inv)) { // Accept D4 condition
			break;
		}
		// reject everything, go back to the start
	}
	return S;
}

// Assembly:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x50, %rsp
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r14
movsd (%rsi), %xmm0
movsd (%rdx), %xmm2
movapd %xmm2, %xmm1
divsd 0x1b18(%rip), %xmm1     # 0x19140
ucomisd %xmm1, %xmm0
jae 0x176e3
ucomisd 0xea6(%rip), %xmm0      # 0x184e0
jne 0x176fe
jp 0x176fe
movapd %xmm2, 0x10(%rsp)
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0xe3e(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0xe46(%rip), %xmm1      # 0x184b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x1aaa(%rip), %xmm0     # 0x19128
mulsd 0x10(%rsp), %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
sarq $0x3f, %rcx
movsd 0x1a9b(%rip), %xmm2     # 0x19138
subsd %xmm2, %xmm0
cvttsd2si %xmm0, %r12
andq %rcx, %r12
movsd (%rbx), %xmm1
movapd %xmm1, %xmm0
subsd %xmm2, %xmm0
cvttsd2si %xmm0, %rcx
orq %rax, %r12
movapd %xmm1, 0x10(%rsp)
cvttsd2si %xmm1, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rcx, %rdx
orq %rax, %rdx
cmpq %rdx, %r12
je 0x1764c
jmp 0x17977
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
addq $0x50, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x1748a
movsd 0xdda(%rip), %xmm4      # 0x184e0
movapd %xmm4, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, 0x38(%rsp)
movsd 0x1a14(%rip), %xmm1     # 0x19130
addsd %xmm0, %xmm1
movapd %xmm4, %xmm3
addsd %xmm4, %xmm2
subsd %xmm0, %xmm2
cvttsd2si %xmm2, %rax
divsd %xmm1, %xmm3
movsd %xmm3, 0x28(%rsp)
movq %rax, %rcx
sarq $0x3f, %rcx
movapd %xmm2, 0x10(%rsp)
movapd %xmm2, %xmm0
subsd 0x19e4(%rip), %xmm0     # 0x19138
cvttsd2si %xmm0, %r13
andq %rcx, %r13
orq %rax, %r13
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
punpckldq 0xd2b(%rip), %xmm1 # xmm1 = xmm1[0],mem[0],xmm1[1],mem[1]
subpd 0xd33(%rip), %xmm1      # 0x184b0
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x1997(%rip), %xmm0     # 0x19128
movsd 0x38(%rsp), %xmm1
callq 0x44d0
movsd 0xd3c(%rip), %xmm1      # 0x184e0
subsd %xmm0, %xmm1
mulsd (%rbx), %xmm1
movsd %xmm1, 0x8(%rsp)
movapd %xmm1, %xmm0
callq 0x4490
cvttsd2si %xmm0, %rax
movq %rax, %rcx
subsd 0x196d(%rip), %xmm0     # 0x19138
cvttsd2si %xmm0, %r12
sarq $0x3f, %rcx
andq %rcx, %r12
orq %rax, %r12
cmpq %r13, %r12
jae 0x1775f
movq (%r14), %rdi
movq (%rdi), %rax
callq *0x10(%rax)
movq %rax, %xmm1
movq 0xcab(%rip), %xmm3      # 0x184a0
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
movapd 0xcaf(%rip), %xmm2      # 0x184b0
subpd %xmm2, %xmm1
movapd %xmm1, %xmm0
unpckhpd %xmm1, %xmm0            # xmm0 = xmm0[1],xmm1[1]
addsd %xmm1, %xmm0
mulsd 0x190f(%rip), %xmm0     # 0x19128
movq %r12, %xmm1
punpckldq %xmm3, %xmm1    # xmm1 = xmm1[0],xmm3[0],xmm1[1],xmm3[1]
subpd %xmm2, %xmm1
movapd %xmm1, %xmm2
unpckhpd %xmm1, %xmm2            # xmm2 = xmm2[1],xmm1[1]
addsd %xmm1, %xmm2
movapd %xmm2, 0x40(%rsp)
mulsd (%rbx), %xmm0
divsd 0x10(%rsp), %xmm0
movsd 0x28(%rsp), %xmm1
callq 0x44d0
movapd 0x40(%rsp), %xmm10
movapd 0x10(%rsp), %xmm5
movsd (%rbx), %xmm9
movsd 0x8(%rsp), %xmm8
movapd %xmm8, %xmm2
divsd %xmm9, %xmm2
movsd 0xc68(%rip), %xmm3      # 0x184e0
movapd %xmm3, %xmm1
subsd %xmm2, %xmm1
mulsd %xmm0, %xmm1
movapd %xmm5, %xmm4
subsd %xmm10, %xmm4
movapd %xmm5, %xmm2
divsd %xmm4, %xmm2
mulsd %xmm1, %xmm2
ucomisd %xmm2, %xmm3
ja 0x17977
movapd %xmm3, %xmm6
movsd %xmm0, 0x30(%rsp)
movsd (%r15), %xmm4
movapd %xmm4, %xmm0
movsd 0x1872(%rip), %xmm7     # 0x19130
addsd %xmm7, %xmm0
movapd %xmm9, %xmm3
subsd %xmm10, %xmm3
cmpltsd %xmm0, %xmm10
movapd %xmm10, %xmm0
andpd %xmm3, %xmm0
movapd %xmm10, %xmm1
andnpd %xmm5, %xmm1
orpd %xmm0, %xmm1
movapd %xmm9, %xmm2
addsd %xmm7, %xmm2
ucomisd %xmm1, %xmm2
movapd %xmm6, %xmm0
jb 0x1793c
movapd %xmm9, %xmm0
subsd %xmm4, %xmm0
addsd %xmm7, %xmm3
andpd %xmm10, %xmm0
andnpd %xmm3, %xmm10
orpd %xmm0, %xmm10
movapd %xmm9, %xmm3
movapd %xmm6, %xmm0
addsd %xmm7, %xmm3
mulsd %xmm3, %xmm0
divsd %xmm10, %xmm0
addsd %xmm7, %xmm10
addsd %xmm7, %xmm2
ucomisd %xmm1, %xmm2
jae 0x17920
movapd %xmm9, %xmm1
subsd %xmm8, %xmm1
divsd %xmm1, %xmm9
movsd %xmm9, 0x8(%rsp)
movsd 0x28(%rsp), %xmm1
callq 0x44d0
movsd 0x30(%rsp), %xmm1
mulsd %xmm0, %xmm1
movsd 0x8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x1775f
movq %r12, %rax
addq $0x50, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq