// File: ashlall[P]StreamStats/Test/./../SourceCode/ChiSquare/ChiSquareCategorical.cpp
// Function: ChiSquareCategorical::calculate_statistic(ChiSquareCategorical const&, int)
double ChiSquareCategorical::calculate_statistic(const ChiSquareCategorical& second_distribution, int seed)
{      	//Getting the size of both streams
	int stream_size_1=stream_size;
	int stream_size_2=second_distribution.stream_size;
	srand(seed);
	
	double constant_1 = sqrt((double)stream_size_2/stream_size_1);
	double constant_2 = sqrt((double)stream_size_1/stream_size_2);
	double estimateSum = 0.0;
	int count = 0;
	for ( auto it = map.begin(); it != map.end(); ++it )
	{
		 // Getting the frequencies if the i'th bin from the two streams.
		 int frequency_1= it->second;
		 int frequency_2 = 0;
		 if (second_distribution.map.find(it->first) != second_distribution.map.end())
		   frequency_2= second_distribution.map.at(it->first);
	 	
		 //Calculating the Chi-Squared Statistic
		
		 // Naive sampling:
		 double value = frequency_1 * constant_1 - frequency_2 * constant_2;
		 chi_squared += (100.0/percent) * (value * value) / (frequency_1 + frequency_2);
	}

	// loop through second stream to find bins where 1st stream is 0
	for (auto i = second_distribution.map.begin(); i != second_distribution.map.end(); ++i)
        {
	  if (map.find(i->first) == map.end())
	  {
	    int frequency_1 = 0;
	    int frequency_2 = i->second;
	    double value = frequency_1 * constant_1 - frequency_2 * constant_2;
	    chi_squared += (100.0/percent) * (value * value) / (frequency_1 + frequency_2);
	  }
	}
		 
		 
		 /*
		 // AMS-sampling from https://people.cs.umass.edu/~mcgregor/papers/07-unsketchables.pdf
		 int r, s;
		 double X;
		 if (rand() % 2 == 0) // randomly pick between stream 1 and stream 2
		 {
		     r = (1 + rand() % stream_size_2) + (rand() % frequency_1) * stream_size_2;
		     s = frequency_2 * stream_size_1;
		     X = 2.0 * ((double)(r * s) / (r + s) - ((double)(r - 1)*s)/(r + s - 1));  
		 }
		 else
		 {
		     r = 0;
		     s = (1 + rand() % stream_size_1) + (rand() % frequency_2) * stream_size_1;
		     X = 2.0 * ((double)(r * s) / (r + s) - ((double)r*(s - 1))/(r + s - 1));
		 }
		 
		 estimateSum += X;
		 count++;
		 */
	
	
	return chi_squared;
	//return (stream_size_1 + stream_size_2 - 4 * stream_size_1 * estimateSum / count);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xc0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xa8(%rbp)
movl 0x20(%rax), %eax
movl %eax, -0x18(%rbp)
movq -0x10(%rbp), %rax
movl 0x20(%rax), %eax
movl %eax, -0x1c(%rbp)
movl -0x14(%rbp), %edi
callq 0x10e0
cvtsi2sdl -0x1c(%rbp), %xmm0
cvtsi2sdl -0x18(%rbp), %xmm1
divsd %xmm1, %xmm0
callq 0x10a0
movsd %xmm0, -0x28(%rbp)
cvtsi2sdl -0x18(%rbp), %xmm0
cvtsi2sdl -0x1c(%rbp), %xmm1
divsd %xmm1, %xmm0
callq 0x10a0
movq -0xa8(%rbp), %rdi
movsd %xmm0, -0x30(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
addq $0x30, %rdi
callq 0x30b0
movq %rax, -0x48(%rbp)
movq -0xa8(%rbp), %rdi
addq $0x30, %rdi
callq 0x3110
movq %rax, -0x50(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x30e0
testb $0x1, %al
jne 0x15c6
jmp 0x16d5
leaq -0x48(%rbp), %rdi
callq 0x3140
movl 0x8(%rax), %eax
movl %eax, -0x54(%rbp)
movl $0x0, -0x58(%rbp)
movq -0x10(%rbp), %rax
addq $0x30, %rax
movq %rax, -0xb0(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x3140
movq -0xb0(%rbp), %rdi
movq %rax, %rsi
callq 0x3170
movq %rax, -0x60(%rbp)
movq -0x10(%rbp), %rdi
addq $0x30, %rdi
callq 0x31a0
movq %rax, -0x68(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x30e0
testb $0x1, %al
jne 0x162b
jmp 0x1657
movq -0x10(%rbp), %rax
addq $0x30, %rax
movq %rax, -0xb8(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x3140
movq -0xb8(%rbp), %rdi
movq %rax, %rsi
callq 0x31d0
movl (%rax), %eax
movl %eax, -0x58(%rbp)
movq -0xa8(%rbp), %rax
cvtsi2sdl -0x54(%rbp), %xmm0
movsd -0x28(%rbp), %xmm2
cvtsi2sdl -0x58(%rbp), %xmm1
mulsd -0x30(%rbp), %xmm1
movq %xmm1, %rcx
movabsq $-0x8000000000000000, %rdx # imm = 0x8000000000000000
xorq %rdx, %rcx
movq %rcx, %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x70(%rbp)
movsd 0x496a(%rip), %xmm0     # 0x6008
divsd 0x10(%rax), %xmm0
movsd -0x70(%rbp), %xmm1
mulsd -0x70(%rbp), %xmm1
mulsd %xmm1, %xmm0
movl -0x54(%rbp), %ecx
addl -0x58(%rbp), %ecx
cvtsi2sd %ecx, %xmm1
divsd %xmm1, %xmm0
addsd (%rax), %xmm0
movsd %xmm0, (%rax)
leaq -0x48(%rbp), %rdi
callq 0x3200
jmp 0x159c
movq -0x10(%rbp), %rdi
addq $0x30, %rdi
callq 0x3230
movq %rax, -0x78(%rbp)
movq -0x10(%rbp), %rdi
addq $0x30, %rdi
callq 0x31a0
movq %rax, -0x80(%rbp)
leaq -0x78(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x30e0
testb $0x1, %al
jne 0x170d
jmp 0x1825
movq -0xa8(%rbp), %rax
addq $0x30, %rax
movq %rax, -0xc0(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x32c0
movq -0xc0(%rbp), %rdi
movq %rax, %rsi
callq 0x3290
movq -0xa8(%rbp), %rdi
movq %rax, -0x88(%rbp)
addq $0x30, %rdi
callq 0x3110
movq %rax, -0x90(%rbp)
leaq -0x88(%rbp), %rdi
leaq -0x90(%rbp), %rsi
callq 0x3260
testb $0x1, %al
jne 0x1771
jmp 0x1815
movl $0x0, -0x94(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x32c0
movq %rax, %rcx
movq -0xa8(%rbp), %rax
movl 0x8(%rcx), %ecx
movl %ecx, -0x98(%rbp)
cvtsi2sdl -0x94(%rbp), %xmm0
movsd -0x28(%rbp), %xmm2
cvtsi2sdl -0x98(%rbp), %xmm1
mulsd -0x30(%rbp), %xmm1
movq %xmm1, %rcx
movabsq $-0x8000000000000000, %rdx # imm = 0x8000000000000000
xorq %rdx, %rcx
movq %rcx, %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0xa0(%rbp)
movsd 0x4828(%rip), %xmm0     # 0x6008
divsd 0x10(%rax), %xmm0
movsd -0xa0(%rbp), %xmm1
mulsd -0xa0(%rbp), %xmm1
mulsd %xmm1, %xmm0
movl -0x94(%rbp), %ecx
addl -0x98(%rbp), %ecx
cvtsi2sd %ecx, %xmm1
divsd %xmm1, %xmm0
addsd (%rax), %xmm0
movsd %xmm0, (%rax)
jmp 0x1817
leaq -0x78(%rbp), %rdi
callq 0x32f0
jmp 0x16e6
movq -0xa8(%rbp), %rax
movsd (%rax), %xmm0
addq $0xc0, %rsp
popq %rbp
retq
nopl (%rax)