// File: nikosgalanis[P]Vectors-Similarity-Search-and-Clustering/programs/Hypercube/../../algorithms/Search/Hypercube/headers/hypercube.h
// Function: Hypercube<double>::Hypercube(unsigned int, unsigned long, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, std::vector<std::vector<double, std::allocator<double>>, std::allocator<std::vector<double, std::allocator<double>>>>)
Hypercube(const uint32_t k, uint64_t m, uint32_t threshold, uint32_t max_probes, 
		uint32_t n_points, uint32_t w, uint32_t space_dim, std::vector<std::vector<T>> init_vectors) : 
		k(k), m(m), threshold(threshold), max_probes(max_probes), n_points(n_points), 
		w(w), space_dim(space_dim), feature_vectors(init_vectors) {
			//measure the time that it takes to initialize the hypercube
			time_t start, finish;
			fprintf(stdout, "Hypercube initialization with parameters: k = %d, m = %ld, threshold = %d"
			" max_probes = %d, npoints = %d, w = %d, spacedim = %d\n", k, m, threshold, max_probes, n_points, w, space_dim);
			time(&start);

			// we have a bit swquence of k bits, thus the size of the hypercube table will be 2^k
			n_buckets = (uint32_t)pow(2, k);

			// Initialize the hash functions of each bucket
			for (uint32_t i = 0; i < k; i++) {
				lsh::HashFunction hash_fn(space_dim, w, m, n_buckets);
				// Insert each amplified hash fn into the apropriate list
				hash_fns.push_back(hash_fn);         
			}

			// initialize the hypercube table
			for (uint32_t i = 0; i < n_buckets; i++) {
				std::list<int> current_list;
				hypercube.push_back(current_list);
			}

			// define the generator and the random distribution for the mapping
			std::random_device mch;
			std::default_random_engine generator(mch());
			std::uniform_int_distribution<int> distribution(0,1);
			
			// create the list of the f functions
			for (uint32_t i = 0; i < k; i++) {
				std::unordered_map<int,bool> current_map;
				// pre-map all the possible hash function outcomes to 0-1, so we buy time during initialization
				for (uint32_t i = 0; i < n_buckets; i++) {
					bool result = distribution(generator);
					current_map.insert({i, result});
				}
				flipped_coins.push_back(current_map);
			}

			// insert all of the points into the hypercube
			for (uint32_t i = 0; i < n_points; i++) {
				int bucket_int = hash_to_hypercube(feature_vectors.at(i));
				hypercube[bucket_int].push_back(i);
			}

			// hypercube initialization done. print the time differenct
			time(&finish);
			cout << "Initialization completed in " << difftime(finish, start) << " seconds" << endl;
		}

// Assembly:
subq $0x1578, %rsp           # imm = 0x1578
movq 0x1590(%rsp), %rax
movq %rax, 0x90(%rsp)
movl 0x1588(%rsp), %eax
movl 0x1580(%rsp), %eax
movq %rdi, 0x1570(%rsp)
movl %esi, 0x156c(%rsp)
movq %rdx, 0x1560(%rsp)
movl %ecx, 0x155c(%rsp)
movl %r8d, 0x1558(%rsp)
movl %r9d, 0x1554(%rsp)
movq 0x1570(%rsp), %rdi
movq %rdi, 0x88(%rsp)
movl 0x156c(%rsp), %eax
movl %eax, (%rdi)
movq 0x1560(%rsp), %rax
movq %rax, 0x8(%rdi)
movl 0x155c(%rsp), %eax
movl %eax, 0x10(%rdi)
movl 0x1558(%rsp), %eax
movl %eax, 0x14(%rdi)
movl 0x1554(%rsp), %eax
movl %eax, 0x18(%rdi)
movl 0x1580(%rsp), %eax
movl %eax, 0x1c(%rdi)
movl 0x1588(%rsp), %eax
movl %eax, 0x20(%rdi)
addq $0x28, %rdi
movq %rdi, 0x80(%rsp)
callq 0x9a40
movq 0x88(%rsp), %rdi
movq 0x90(%rsp), %rsi
addq $0x40, %rdi
movq %rdi, 0x98(%rsp)
callq 0x6540
jmp 0x675e
movq 0x88(%rsp), %rdi
addq $0x58, %rdi
movq %rdi, 0x68(%rsp)
callq 0x9a50
movq 0x88(%rsp), %rdi
addq $0x70, %rdi
movq %rdi, 0x70(%rsp)
callq 0x9a60
movq 0x13827(%rip), %rax     # 0x19fb8
movq (%rax), %rdi
movl 0x156c(%rsp), %edx
movq 0x1560(%rsp), %rcx
movl 0x155c(%rsp), %r8d
movl 0x1558(%rsp), %r9d
movl 0x1554(%rsp), %esi
movl 0x1580(%rsp), %r10d
movl 0x1588(%rsp), %r11d
movq %rsp, %rax
movl %r11d, 0x10(%rax)
movl %r10d, 0x8(%rax)
movl %esi, (%rax)
leaq 0xbbcc(%rip), %rsi      # 0x123aa
xorl %eax, %eax
callq 0x22c0
leaq 0x1538(%rsp), %rdi
callq 0x2190
movl 0x156c(%rsp), %esi
movl $0x2, %edi
callq 0x9a70
movsd %xmm0, 0x78(%rsp)
jmp 0x680b
movq 0x88(%rsp), %rax
movsd 0x78(%rsp), %xmm0
cvttsd2si %xmm0, %rcx
movl %ecx, 0x24(%rax)
movl $0x0, 0x152c(%rsp)
movl 0x152c(%rsp), %eax
cmpl 0x156c(%rsp), %eax
jae 0x690a
movq 0x88(%rsp), %rax
movl 0x1588(%rsp), %esi
movl 0x1580(%rsp), %ecx
cvtsi2sd %rcx, %xmm0
movl 0x1560(%rsp), %edx
movl 0x24(%rax), %ecx
leaq 0x14e0(%rsp), %rdi
callq 0x9a90
jmp 0x6874
movq 0x88(%rsp), %rdi
addq $0x58, %rdi
leaq 0x14e0(%rsp), %rsi
callq 0x9d70
jmp 0x688f
leaq 0x14e0(%rsp), %rdi
callq 0x9db0
movl 0x152c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x152c(%rsp)
jmp 0x682c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
jmp 0x6d03
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
jmp 0x6ce2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
leaq 0x14e0(%rsp), %rdi
callq 0x9db0
jmp 0x6ce2
movl $0x0, 0x14dc(%rsp)
movq 0x88(%rsp), %rcx
movl 0x14dc(%rsp), %eax
cmpl 0x24(%rcx), %eax
jae 0x6999
leaq 0x14c0(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x9de0
movq 0x88(%rsp), %rdi
movq 0x60(%rsp), %rsi
addq $0x28, %rdi
callq 0x9df0
jmp 0x6953
leaq 0x14c0(%rsp), %rdi
callq 0x9e60
movl 0x14dc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x14dc(%rsp)
jmp 0x6915
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
leaq 0x14c0(%rsp), %rdi
callq 0x9e60
jmp 0x6ce2
leaq 0x138(%rsp), %rdi
callq 0x9e70
jmp 0x69a8
leaq 0x138(%rsp), %rdi
callq 0x9f10
movl %eax, 0x5c(%rsp)
jmp 0x69bb
movl 0x5c(%rsp), %eax
movl %eax, %eax
movl %eax, %esi
leaq 0x130(%rsp), %rdi
callq 0x9f20
jmp 0x69d2
leaq 0x128(%rsp), %rdi
xorl %esi, %esi
movl $0x1, %edx
callq 0x9f50
jmp 0x69e8
movl $0x0, 0x124(%rsp)
movl 0x124(%rsp), %eax
cmpl 0x156c(%rsp), %eax
jae 0x6b4a
leaq 0xe8(%rsp), %rdi
callq 0x9f80
movl $0x0, 0xe4(%rsp)
movq 0x88(%rsp), %rcx
movl 0xe4(%rsp), %eax
cmpl 0x24(%rcx), %eax
jae 0x6b0c
leaq 0x128(%rsp), %rdi
leaq 0x130(%rsp), %rsi
callq 0x9f90
movl %eax, 0x58(%rsp)
jmp 0x6a52
movl 0x58(%rsp), %eax
testl %eax, %eax
setne 0xe3(%rsp)
leaq 0xd8(%rsp), %rdi
leaq 0xe4(%rsp), %rsi
leaq 0xe3(%rsp), %rdx
callq 0xa010
jmp 0x6a7f
leaq 0xe8(%rsp), %rdi
leaq 0xd8(%rsp), %rsi
callq 0x9fc0
movb %dl, 0x4f(%rsp)
movq %rax, 0x50(%rsp)
jmp 0x6a9f
movb 0x4f(%rsp), %al
movq 0x50(%rsp), %rcx
movq %rcx, 0xc8(%rsp)
movb %al, 0xd0(%rsp)
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe4(%rsp)
jmp 0x6a1f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
jmp 0x6cd5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0xa0b0
jmp 0x6cd5
movq 0x88(%rsp), %rdi
addq $0x70, %rdi
leaq 0xe8(%rsp), %rsi
callq 0xa040
jmp 0x6b27
leaq 0xe8(%rsp), %rdi
callq 0xa0b0
movl 0x124(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x124(%rsp)
jmp 0x69f3
movl $0x0, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
cmpl 0x1554(%rsp), %eax
jae 0x6c48
movq 0x88(%rsp), %rdi
addq $0x40, %rdi
movl 0xc4(%rsp), %eax
movl %eax, %esi
callq 0x6640
movq %rax, 0x40(%rsp)
jmp 0x6b8a
movq 0x40(%rsp), %rsi
leaq 0xa8(%rsp), %rdi
callq 0x4560
jmp 0x6b9e
movq 0x88(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0xa0c0
movl %eax, 0x3c(%rsp)
jmp 0x6bb9
leaq 0xa8(%rsp), %rdi
callq 0x3510
movl 0x3c(%rsp), %eax
movq 0x88(%rsp), %rdi
movl %eax, 0xc0(%rsp)
addq $0x28, %rdi
movslq 0xc0(%rsp), %rsi
callq 0xa2e0
movq %rax, %rdi
movl 0xc4(%rsp), %eax
movl %eax, 0xa4(%rsp)
leaq 0xa4(%rsp), %rsi
callq 0xa300
jmp 0x6c0a
jmp 0x6c0c
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x6b55
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1548(%rsp)
movl %eax, 0x1544(%rsp)
leaq 0xa8(%rsp), %rdi
callq 0x3510
jmp 0x6cd5
leaq 0x1530(%rsp), %rdi
callq 0x2190
movq 0x1337c(%rip), %rdi     # 0x19fd8
leaq 0xb7c7(%rip), %rsi      # 0x1242a
callq 0x21c0
movq %rax, 0x30(%rsp)
jmp 0x6c6f
movq 0x1530(%rsp), %rdi
movq 0x1538(%rsp), %rsi
callq 0x20d0
movq 0x30(%rsp), %rdi
callq 0x2400
movq %rax, 0x28(%rsp)
jmp 0x6c95
movq 0x28(%rsp), %rdi
leaq 0xb7a6(%rip), %rsi      # 0x12447
callq 0x21c0
movq %rax, 0x20(%rsp)
jmp 0x6cad
movq 0x20(%rsp), %rdi
movq 0x1330f(%rip), %rsi     # 0x19fc8
callq 0x21e0
jmp 0x6cc0
leaq 0x138(%rsp), %rdi
callq 0xa340
addq $0x1578, %rsp           # imm = 0x1578
retq
leaq 0x138(%rsp), %rdi
callq 0xa340
movq 0x70(%rsp), %rdi
callq 0xa360
movq 0x68(%rsp), %rdi
callq 0xa3c0
movq 0x98(%rsp), %rdi
callq 0x3570
movq 0x80(%rsp), %rdi
callq 0xa3d0
movq 0x1548(%rsp), %rdi
callq 0x23c0
nopl (%rax)