// File: CominLab[P]QCluster/em.cc
// Function: hard_em(int, int, int, double**, double**, double*, double**, double*, int, double**, int*, double*, int, char, int)
int hard_em(int K, int N, int row_length, double** data, 
		double **quality, double *expected_qual, double **quality_1, double *expected_freq,
		int num_nt, double** data_1, int* assignment, double *Z, 
		int num_trials, char dist_type, int verbose)
{
	// Allocate matrices for centroids, distances, assignment and the 
	// vector for the number of members
	double**  centroids = new double*[K];
	centroids[0] = new double[row_length*K];
	for(int k=1; k<K; ++k) {
		centroids[k] = centroids[0] + k*row_length;
	} // K*row_length matrix for centroid locations

	double**  centroids_tilde = new double*[K];
	centroids_tilde[0] = new double[row_length*K];
	for(int k=1; k<K; ++k) {
		centroids_tilde[k] = centroids_tilde[0] + k*row_length;
	} // K*row_length matrix for X_tilde vars for centroids

	int* tmp_assignment = new int[N];
	int *numMembers = new int[K];  // number of members in each cluster
	double** tmp_data = new double*[N];
	double** tmp_data_1 = new double*[N];

	// call clustering routine
	double min_distortion = 0;
	for (int t=0; t<num_trials; t++) {
		if (verbose > 0) {
			cerr<<"Calling EM routine, attempt "<<t+1<<endl;
		}
		double distortion =	em_routine(K, N, row_length, data, quality, 
				expected_qual, quality_1, expected_freq, num_nt, data_1,
				tmp_assignment, numMembers, centroids, centroids_tilde,
				tmp_data, tmp_data_1, dist_type, verbose);
		if (verbose > 0) {
			cerr<<"Resulting distortion: "<<distortion<<endl;
		}
		if (!t || (distortion < min_distortion)) {
			if (verbose > 0) {
				cerr<<"Updating best partitioning and minimal distortion"<<endl;
			}
			min_distortion = distortion;
			memcpy(assignment, tmp_assignment, N*sizeof(*assignment));
		}
	}
	if (verbose > 0) {
		cerr<<"Resulting minimal distortion: "<<min_distortion<<endl;
	}
	//evaluate confidence if using KL with raw counts
	if (dist_type == 'k') {
		eval_confidence(K, N, row_length, data, centroids, Z, quality, expected_qual, expected_freq);
	}
	// delete allocated arrays
	delete[] centroids[0];
	delete[] centroids;
	delete[] centroids_tilde[0];
	delete[] centroids_tilde;
	delete[] numMembers;
	delete[] tmp_data;
	delete[] tmp_data_1;
	delete[] tmp_assignment;

	// return the number of clusters
	return count_num_clusters(N, assignment);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x158, %rsp            # imm = 0x158
movl 0x50(%rbp), %eax
movb 0x48(%rbp), %al
movl 0x40(%rbp), %eax
movq 0x38(%rbp), %rax
movq 0x30(%rbp), %rax
movq 0x28(%rbp), %rax
movl 0x20(%rbp), %eax
movq 0x18(%rbp), %rax
movq 0x10(%rbp), %rax
movl %edi, -0x2c(%rbp)
movl %esi, -0x30(%rbp)
movl %edx, -0x34(%rbp)
movq %rcx, -0x40(%rbp)
movq %r8, -0x48(%rbp)
movq %r9, -0x50(%rbp)
movslq -0x2c(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x58(%rbp)
movl -0x34(%rbp), %eax
imull -0x2c(%rbp), %eax
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, %rcx
movq -0x58(%rbp), %rax
movq %rcx, (%rax)
movl $0x1, -0x5c(%rbp)
movl -0x5c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x5ff3
movq -0x58(%rbp), %rax
movq (%rax), %rdx
movl -0x5c(%rbp), %eax
imull -0x34(%rbp), %eax
cltq
shlq $0x3, %rax
addq %rax, %rdx
movq -0x58(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x5fbd
movslq -0x2c(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x68(%rbp)
movl -0x34(%rbp), %eax
imull -0x2c(%rbp), %eax
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, %rcx
movq -0x68(%rbp), %rax
movq %rcx, (%rax)
movl $0x1, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x608d
movq -0x68(%rbp), %rax
movq (%rax), %rdx
movl -0x6c(%rbp), %eax
imull -0x34(%rbp), %eax
cltq
shlq $0x3, %rax
addq %rax, %rdx
movq -0x68(%rbp), %rax
movslq -0x6c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x6057
movslq -0x30(%rbp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x78(%rbp)
movslq -0x2c(%rbp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x80(%rbp)
movslq -0x30(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x88(%rbp)
movslq -0x30(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x90(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x98(%rbp)
movl $0x0, -0x9c(%rbp)
movl -0x9c(%rbp), %eax
cmpl 0x40(%rbp), %eax
jge 0x632d
cmpl $0x0, 0x50(%rbp)
jle 0x6194
movq 0x8e88(%rip), %rdi      # 0xeff0
leaq 0x5a71(%rip), %rsi      # 0xbbe0
callq 0x3260
movq %rax, %rdi
movl -0x9c(%rbp), %esi
addl $0x1, %esi
callq 0x3400
movq %rax, %rdi
movq 0x8e21(%rip), %rsi      # 0xefb0
callq 0x32a0
movl -0x2c(%rbp), %edi
movl -0x30(%rbp), %esi
movl -0x34(%rbp), %edx
movq -0x40(%rbp), %rcx
movq -0x48(%rbp), %r8
movq -0x50(%rbp), %r9
movq 0x10(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq 0x18(%rbp), %rax
movq %rax, -0xc8(%rbp)
movl 0x20(%rbp), %eax
movl %eax, -0xbc(%rbp)
movq 0x28(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x78(%rbp), %r13
movq -0x80(%rbp), %r12
movq -0x58(%rbp), %r15
movq -0x68(%rbp), %r14
movq -0x88(%rbp), %rbx
movq -0x90(%rbp), %r11
movb 0x48(%rbp), %r10b
movl 0x50(%rbp), %eax
movl %eax, -0xac(%rbp)
xorl %eax, %eax
movq -0xd0(%rbp), %rax
movq %rax, (%rsp)
movq -0xc8(%rbp), %rax
movq %rax, 0x8(%rsp)
movl -0xbc(%rbp), %eax
movl %eax, 0x10(%rsp)
movq -0xb8(%rbp), %rax
movq %rax, 0x18(%rsp)
movl -0xac(%rbp), %eax
movq %r13, 0x20(%rsp)
movq %r12, 0x28(%rsp)
movq %r15, 0x30(%rsp)
movq %r14, 0x38(%rsp)
movq %rbx, 0x40(%rsp)
movq %r11, 0x48(%rsp)
movsbl %r10b, %r10d
movl %r10d, 0x50(%rsp)
movl %eax, 0x58(%rsp)
movl $0x0, 0x60(%rsp)
callq 0x64c0
movsd %xmm0, -0xa8(%rbp)
cmpl $0x0, 0x50(%rbp)
jle 0x62ab
movq 0x8d70(%rip), %rdi      # 0xeff0
leaq 0x5976(%rip), %rsi      # 0xbbfd
callq 0x3260
movq %rax, %rdi
movsd -0xa8(%rbp), %xmm0
callq 0x3480
movq %rax, %rdi
movq 0x8d0a(%rip), %rsi      # 0xefb0
callq 0x32a0
cmpl $0x0, -0x9c(%rbp)
je 0x62ca
movsd -0xa8(%rbp), %xmm1
movsd -0x98(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x6317
cmpl $0x0, 0x50(%rbp)
jle 0x62f2
movq 0x8d19(%rip), %rdi      # 0xeff0
leaq 0x5936(%rip), %rsi      # 0xbc14
callq 0x3260
movq %rax, %rdi
movq 0x8cc3(%rip), %rsi      # 0xefb0
callq 0x32a0
movsd -0xa8(%rbp), %xmm0
movsd %xmm0, -0x98(%rbp)
movq 0x30(%rbp), %rdi
movq -0x78(%rbp), %rsi
movslq -0x30(%rbp), %rdx
shlq $0x2, %rdx
callq 0x3200
jmp 0x6319
movl -0x9c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x9c(%rbp)
jmp 0x614c
cmpl $0x0, 0x50(%rbp)
jle 0x6365
movq 0x8cb6(%rip), %rdi      # 0xeff0
leaq 0x5905(%rip), %rsi      # 0xbc46
callq 0x3260
movq %rax, %rdi
movsd -0x98(%rbp), %xmm0
callq 0x3480
movq %rax, %rdi
movq 0x8c50(%rip), %rsi      # 0xefb0
callq 0x32a0
movsbl 0x48(%rbp), %eax
cmpl $0x6b, %eax
jne 0x63a2
movl -0x2c(%rbp), %edi
movl -0x30(%rbp), %esi
movl -0x34(%rbp), %edx
movq -0x40(%rbp), %rcx
movq -0x58(%rbp), %r8
movq 0x38(%rbp), %r9
movq -0x48(%rbp), %r11
movq -0x50(%rbp), %r10
movq 0x18(%rbp), %rax
movq %r11, (%rsp)
movq %r10, 0x8(%rsp)
movq %rax, 0x10(%rsp)
callq 0x6c00
movq -0x58(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xd8(%rbp)
cmpq $0x0, %rax
je 0x63c2
movq -0xd8(%rbp), %rdi
callq 0x3350
movq -0x58(%rbp), %rax
movq %rax, -0xe0(%rbp)
cmpq $0x0, %rax
je 0x63df
movq -0xe0(%rbp), %rdi
callq 0x3350
movq -0x68(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xe8(%rbp)
cmpq $0x0, %rax
je 0x63ff
movq -0xe8(%rbp), %rdi
callq 0x3350
movq -0x68(%rbp), %rax
movq %rax, -0xf0(%rbp)
cmpq $0x0, %rax
je 0x641c
movq -0xf0(%rbp), %rdi
callq 0x3350
movq -0x80(%rbp), %rax
movq %rax, -0xf8(%rbp)
cmpq $0x0, %rax
je 0x6439
movq -0xf8(%rbp), %rdi
callq 0x3350
movq -0x88(%rbp), %rax
movq %rax, -0x100(%rbp)
cmpq $0x0, %rax
je 0x6459
movq -0x100(%rbp), %rdi
callq 0x3350
movq -0x90(%rbp), %rax
movq %rax, -0x108(%rbp)
cmpq $0x0, %rax
je 0x6479
movq -0x108(%rbp), %rdi
callq 0x3350
movq -0x78(%rbp), %rax
movq %rax, -0x110(%rbp)
cmpq $0x0, %rax
je 0x6496
movq -0x110(%rbp), %rdi
callq 0x3350
movl -0x30(%rbp), %edi
movq 0x30(%rbp), %rsi
callq 0x6e10
addq $0x158, %rsp            # imm = 0x158
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nopw %cs:(%rax,%rax)