// File: nikosgalanis[P]Vectors-Similarity-Search-and-Clustering/programs/LSH/../../algorithms/Search/LSH/headers/lsh.h
// Function: LSH<double>::kNearestNeighbour[abi:cxx11](std::vector<double, std::allocator<double>>, int)
list<pair<int,T>> kNearestNeighbour(std::vector<T> query_vector, int k) {
						
					list<pair<int,T>> result;

					//the greatest of the k min distances
					T kth_min_distance = (T) INT_MAX;

					int i = 0;
					int visited = 0;

					// Traverse the hash tables
					for (std::list<lsh::AmplifiedHashFunction>::iterator it = amplified_hash_fns.begin(); 
						it != amplified_hash_fns.end(); it++) {
						// find the bucket that the query hashes into
						int index = it->assign_to_bucket(query_vector);
						list<int> bucket = lsh_tables.at(i)[index];
						// get all the indexes of the vectors in the bucket
						for (std::list<int>::iterator bucket_it = bucket.begin(); bucket_it != bucket.end(); bucket_it++) {
							visited++;
							// distance between vectors
							T distance =  metrics::ManhatanDistance(feature_vectors.at(*bucket_it), query_vector, space_dim);
							
							// if the element is already in the list, skip the checks
							pair<int, T> new_pair = make_pair(*bucket_it, distance);
							
							if (find(result.begin(), result.end(), new_pair) != result.end()) {
								continue;
							}

							// insert the pair into the list if it's distance is less than the kth_min
							if (result.size() > 0 && result.size() < (uint64_t) k) {
								// size < k so we just insert it
								
								if (distance >= kth_min_distance) {
									// insert at back if distance > kth_min_distance
									// kth_min_distance is the distance of the last element
									kth_min_distance = distance;
									result.push_back(new_pair);
								} else {
									// iterate through the list to insert it in the right position
									typename std::list<std::pair<int,T>>::iterator pair_it;
									for (pair_it = result.begin(); pair_it !=result.end(); pair_it++) {
										if (distance < pair_it->second) {
											result.insert(pair_it, new_pair);
											break;
										}
									}
								}
							} else if (result.size() > 0 && (result.size() == (uint64_t)k)) {
								// insert, pop the last, and make the kth_min the new last
								if (distance < kth_min_distance) {
									// iterate through the list to insert it in the right position
									for (typename std::list<pair<int,T>>::iterator pair_it = result.begin(); pair_it !=result.end(); pair_it++) {
										if ( distance < pair_it->second) {
											result.insert(pair_it, new_pair);
											break;
										}
									}
									result.pop_back();
									kth_min_distance = result.back().second;
								}
							} else if (result.size() == 0) {
								// size is 0, insert 1st element
								kth_min_distance = distance;
								result.push_back(new_pair);
							}
							// if (visited > 10 * L) {
							//     return b;
							// }
						}
						i++;
					}
					return result;
				}

// Assembly:
subq $0x1f8, %rsp            # imm = 0x1F8
movq %rdx, 0x70(%rsp)
movq %rdi, 0x78(%rsp)
movq %rdi, %rax
movq %rax, 0x80(%rsp)
movq %rdi, 0x1f0(%rsp)
movq %rsi, 0x1e8(%rsp)
movq %rdx, 0x1e0(%rsp)
movl %ecx, 0x1dc(%rsp)
movq 0x1e8(%rsp), %rax
movq %rax, 0x88(%rsp)
movb $0x0, 0x1db(%rsp)
callq 0x8900
movq 0x88(%rsp), %rdi
movsd 0x9470(%rip), %xmm0     # 0x101d8
movsd %xmm0, 0x1d0(%rsp)
movl $0x0, 0x1cc(%rsp)
movl $0x0, 0x1c8(%rsp)
addq $0x20, %rdi
callq 0x9430
movq %rax, 0x1c0(%rsp)
movq 0x88(%rsp), %rdi
addq $0x20, %rdi
callq 0x9480
movq %rax, 0x1b8(%rsp)
leaq 0x1c0(%rsp), %rdi
leaq 0x1b8(%rsp), %rsi
callq 0x9460
testb $0x1, %al
jne 0x6dcf
jmp 0x7422
leaq 0x1c0(%rsp), %rdi
callq 0x95f0
movq 0x70(%rsp), %rsi
movq %rax, 0x68(%rsp)
leaq 0x198(%rsp), %rdi
callq 0x4500
jmp 0x6df5
movq 0x68(%rsp), %rdi
leaq 0x198(%rsp), %rsi
callq 0x9610
movl %eax, 0x64(%rsp)
jmp 0x6e0d
leaq 0x198(%rsp), %rdi
callq 0x34b0
movl 0x64(%rsp), %eax
movq 0x88(%rsp), %rdi
movl %eax, 0x1b4(%rsp)
addq $0x38, %rdi
movslq 0x1cc(%rsp), %rsi
callq 0x94b0
movq %rax, 0x58(%rsp)
jmp 0x6e45
movq 0x58(%rsp), %rdi
movslq 0x1b4(%rsp), %rsi
callq 0x92d0
movq %rax, %rsi
leaq 0x170(%rsp), %rdi
callq 0xe9d0
jmp 0x6e69
leaq 0x170(%rsp), %rdi
callq 0xccb0
movq %rax, 0x168(%rsp)
leaq 0x170(%rsp), %rdi
callq 0xcce0
movq %rax, 0x160(%rsp)
leaq 0x168(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0xcd10
testb $0x1, %al
jne 0x6eb1
jmp 0x73d9
movq 0x88(%rsp), %rax
movl 0x1c8(%rsp), %ecx
incl %ecx
movl %ecx, 0x1c8(%rsp)
addq $0x50, %rax
movq %rax, 0x48(%rsp)
leaq 0x168(%rsp), %rdi
callq 0xcd80
movq 0x48(%rsp), %rdi
movslq (%rax), %rsi
callq 0x62e0
movq %rax, 0x50(%rsp)
jmp 0x6ef3
movq 0x50(%rsp), %rsi
leaq 0x140(%rsp), %rdi
callq 0x4500
jmp 0x6f07
movq 0x70(%rsp), %rsi
leaq 0x128(%rsp), %rdi
callq 0x4500
jmp 0x6f1b
movq 0x88(%rsp), %rax
movl 0x18(%rax), %edx
leaq 0x140(%rsp), %rdi
leaq 0x128(%rsp), %rsi
callq 0x8910
movsd %xmm0, 0x40(%rsp)
jmp 0x6f43
leaq 0x128(%rsp), %rdi
callq 0x34b0
leaq 0x140(%rsp), %rdi
callq 0x34b0
movsd 0x40(%rsp), %xmm0
movsd %xmm0, 0x158(%rsp)
leaq 0x168(%rsp), %rdi
callq 0xcd80
movq %rax, %rdi
leaq 0x158(%rsp), %rsi
callq 0xf520
movsd %xmm0, 0x30(%rsp)
movl %eax, 0x3c(%rsp)
jmp 0x6f95
movq 0x78(%rsp), %rdi
movsd 0x30(%rsp), %xmm0
movl 0x3c(%rsp), %eax
movl %eax, 0x118(%rsp)
movsd %xmm0, 0x120(%rsp)
callq 0x7a80
movq 0x78(%rsp), %rdi
movq %rax, 0x108(%rsp)
callq 0x7ad0
movq %rax, 0x100(%rsp)
movq 0x108(%rsp), %rdi
movq 0x100(%rsp), %rsi
leaq 0x118(%rsp), %rdx
callq 0xf560
movq %rax, 0x28(%rsp)
jmp 0x6ff7
movq 0x78(%rsp), %rdi
movq 0x28(%rsp), %rax
movq %rax, 0x110(%rsp)
callq 0x7ad0
movq %rax, 0xf8(%rsp)
leaq 0x110(%rsp), %rdi
leaq 0xf8(%rsp), %rsi
callq 0x7ab0
testb $0x1, %al
jne 0x7034
jmp 0x70da
jmp 0x73bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x190(%rsp)
movl %eax, 0x18c(%rsp)
jmp 0x744e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x190(%rsp)
movl %eax, 0x18c(%rsp)
leaq 0x198(%rsp), %rdi
callq 0x34b0
jmp 0x744e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x190(%rsp)
movl %eax, 0x18c(%rsp)
jmp 0x7413
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x190(%rsp)
movl %eax, 0x18c(%rsp)
jmp 0x70c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x190(%rsp)
movl %eax, 0x18c(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x34b0
leaq 0x140(%rsp), %rdi
callq 0x34b0
jmp 0x7413
movq 0x78(%rsp), %rdi
callq 0x8a20
cmpq $0x0, %rax
jbe 0x723e
movq 0x78(%rsp), %rdi
callq 0x8a20
movslq 0x1dc(%rsp), %rcx
cmpq %rcx, %rax
jae 0x723e
movsd 0x158(%rsp), %xmm0
ucomisd 0x1d0(%rsp), %xmm0
jb 0x7148
movq 0x78(%rsp), %rdi
movsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x1d0(%rsp)
leaq 0x118(%rsp), %rsi
callq 0x8a50
jmp 0x7143
jmp 0x7239
leaq 0xf0(%rsp), %rdi
callq 0x8a90
movq 0x78(%rsp), %rdi
callq 0x7a80
movq %rax, 0xe8(%rsp)
movq 0xe8(%rsp), %rax
movq %rax, 0xf0(%rsp)
movq 0x78(%rsp), %rdi
callq 0x7ad0
movq %rax, 0xe0(%rsp)
leaq 0xf0(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x7ab0
testb $0x1, %al
jne 0x71a7
jmp 0x7237
movsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
leaq 0xf0(%rsp), %rdi
callq 0x7b00
movsd 0x20(%rsp), %xmm1
movsd 0x8(%rax), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x7219
leaq 0xd8(%rsp), %rdi
leaq 0xf0(%rsp), %rsi
callq 0x8b30
movq 0x78(%rsp), %rdi
movq 0xd8(%rsp), %rsi
leaq 0x118(%rsp), %rdx
callq 0x8ab0
movq %rax, 0x18(%rsp)
jmp 0x720a
movq 0x18(%rsp), %rax
movq %rax, 0xd0(%rsp)
jmp 0x7237
jmp 0x721b
leaq 0xf0(%rsp), %rdi
xorl %esi, %esi
callq 0x7b20
movq %rax, 0xc8(%rsp)
jmp 0x7177
jmp 0x7239
jmp 0x73bb
movq 0x78(%rsp), %rdi
callq 0x8a20
cmpq $0x0, %rax
jbe 0x737f
movq 0x78(%rsp), %rdi
callq 0x8a20
movslq 0x1dc(%rsp), %rcx
cmpq %rcx, %rax
jne 0x737f
movsd 0x158(%rsp), %xmm1
movsd 0x1d0(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x737d
movq 0x78(%rsp), %rdi
callq 0x7a80
movq %rax, 0xc0(%rsp)
movq 0x78(%rsp), %rdi
callq 0x7ad0
movq %rax, 0xb8(%rsp)
leaq 0xc0(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x7ab0
testb $0x1, %al
jne 0x72cb
jmp 0x735b
movsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
leaq 0xc0(%rsp), %rdi
callq 0x7b00
movsd 0x10(%rsp), %xmm1
movsd 0x8(%rax), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x733d
leaq 0xb0(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x8b30
movq 0x78(%rsp), %rdi
movq 0xb0(%rsp), %rsi
leaq 0x118(%rsp), %rdx
callq 0x8ab0
movq %rax, 0x8(%rsp)
jmp 0x732e
movq 0x8(%rsp), %rax
movq %rax, 0xa8(%rsp)
jmp 0x735b
jmp 0x733f
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x7b20
movq %rax, 0xa0(%rsp)
jmp 0x729b
movq 0x78(%rsp), %rdi
callq 0x8b50
movq 0x78(%rsp), %rdi
callq 0x8070
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x1d0(%rsp)
jmp 0x73b9
movq 0x78(%rsp), %rdi
callq 0x8a20
cmpq $0x0, %rax
jne 0x73b7
movq 0x78(%rsp), %rdi
movsd 0x158(%rsp), %xmm0
movsd %xmm0, 0x1d0(%rsp)
leaq 0x118(%rsp), %rsi
callq 0x8a50
jmp 0x73b5
jmp 0x73b7
jmp 0x73b9
jmp 0x73bb
jmp 0x73bd
leaq 0x168(%rsp), %rdi
xorl %esi, %esi
callq 0xf5c0
movq %rax, 0x98(%rsp)
jmp 0x6e7e
movl 0x1cc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1cc(%rsp)
leaq 0x170(%rsp), %rdi
callq 0x9350
leaq 0x1c0(%rsp), %rdi
xorl %esi, %esi
callq 0x96e0
movq %rax, 0x90(%rsp)
jmp 0x6d98
leaq 0x170(%rsp), %rdi
callq 0x9350
jmp 0x744e
movb $0x1, 0x1db(%rsp)
testb $0x1, 0x1db(%rsp)
jne 0x743e
movq 0x78(%rsp), %rdi
callq 0x8000
movq 0x80(%rsp), %rax
addq $0x1f8, %rsp            # imm = 0x1F8
retq
movq 0x78(%rsp), %rdi
callq 0x8000
movq 0x190(%rsp), %rdi
callq 0x2370
nopw %cs:(%rax,%rax)
nop