// File: /workspace/github_cpp_makefile_star2_O3/big-data-lab-team[P]OrpailleCC/./src/mondrian_coarse.hpp
// Function: CoarseMondrianForest<double, funct, KappaMetrics<2, false>, 4, 2, 6000>::split_barycenter(int, int, double const*, int, int, double)
bool split_barycenter(int const node_id, int const tree_id, feature_type const* features, int const label, int const parent_id, double const parent_tau){
	int new_parent_id, new_sibling_id;
	double sum = 0;
	Node& node = nodes()[node_id];
	double barycenter[feature_count];
	double probabilities[feature_count];
	if(split_helper == SPLIT_HELPER_WEIGHTED)
		find_barycenter(tree_bases()[tree_id].root, barycenter);
	else if(split_helper == SPLIT_HELPER_AVG){
		for(int i = 0; i < feature_count; i++){
			barycenter[i] = sum_features[i]/count_points;
		}
	}
	else if(split_helper == SPLIT_HELPER_NONE)
		return false;

	for(int i = 0; i < feature_count; ++i){
		if(barycenter[i] > node.bound_lower[i] && barycenter[i] < node.bound_upper[i]){
			probabilities[i] = Utils::abs(barycenter[i] - features[i]);
			sum += probabilities[i];
		}
		else{
			probabilities[i] = 0;
		}
	}
	double const E = sum == 0 ?  -1 : Utils::rand_exponential<func>(sum);
	if(sum == 0){
		return false;
	}

	Utils::turn_array_into_probability(probabilities, feature_count, sum);
	//sample features with probability proportional to e_lower[i] + e_upper[i]
	int const dimension = Utils::pick_from_distribution<func>(probabilities, feature_count);

	//Select the bound to choose the split from
	double lower_value = Utils::min(barycenter[dimension], features[dimension]);
	double upper_value = Utils::max(barycenter[dimension], features[dimension]);

	//sample the split between [lower_value, upper_value]
	double const random_value = func::rand_uniform();
	double const split_value = random_value*(upper_value - lower_value) + lower_value;

	new_parent_id = available_node();
	nodes()[new_parent_id].tau = parent_tau + (node.tau - parent_tau)*random_value;
	new_sibling_id = available_node();
	nodes()[new_sibling_id].tau = lifetime;
	node_available -= 2;

	Node &new_parent = nodes()[new_parent_id];
	Node &new_sibling = nodes()[new_sibling_id];

	new_parent.split_dimension = dimension;
	new_parent.split_value = split_value;
	//Set the box for the new children and the new_parent and the node (depending on the values in features
	//The current datapoint is passed through after readjusting counters and shape
	for(int i = 0; i < feature_count; ++i){
		new_parent.bound_lower[i] = Utils::min(node.bound_lower[i], features[i]);
		new_parent.bound_upper[i] = Utils::max(node.bound_upper[i], features[i]);
		new_sibling.bound_lower[i] = node.bound_lower[i];
		new_sibling.bound_upper[i] = node.bound_upper[i];
	}

	//Creates counters for the label of the new sibling
	for(int i = 0; i < label_count; ++i)
		new_sibling.counters[i] = 0;
	//No need to increase the counter for the current label because we will do it later, when passing down.

	//Make the connections between the new nodes
	if(!node.has_parent() && node_id == tree_bases()[tree_id].root)//We introduce a parent to the root
		tree_bases()[tree_id].root = new_parent_id;
	else{ //Otherwise, replace the existing pointer to parent
		Node& parent = nodes()[node.parent];
		if(parent.child_left == node_id)
			parent.child_left = new_parent_id;
		else
			parent.child_right = new_parent_id;
	}

	//Count sub-trees !
	int count_left = 0, count_right = 0;
	count_sides(node_id, dimension, split_value, count_left, count_right);
	bool const subtree_on_left = (count_left > count_right);
	//If more count are higher than split ---> new sibling goes left
	//set the connections
	if(subtree_on_left){
		new_parent.child_right = new_sibling_id;
		new_parent.child_left = node_id;
		node.bound_upper[dimension] = split_value;
		new_sibling.bound_lower[dimension] = split_value;
	}
	else{
		new_parent.child_right = node_id;
		new_parent.child_left = new_sibling_id;
		node.bound_lower[dimension] = split_value;
		new_sibling.bound_upper[dimension] = split_value;
	}
	new_parent.parent = node.parent;
	node.parent = new_parent_id;
	new_sibling.parent = new_parent_id;

	//Distribute Forced_extend
	if(fe_distribution == FE_DISTRIBUTION_ZERO){
		node.forced_extend = 0;
		new_sibling.forced_extend = 0;
	}
	else if(fe_distribution == FE_DISTRIBUTION_SPLIT){
		new_sibling.forced_extend = 0.5 * node.forced_extend;
		node.forced_extend *= 0.5;
	}
	else if(fe_distribution == FE_DISTRIBUTION_PROPORTIONAL){
		double const sum_count = static_cast<double>(count_left + count_right);
		double const ratio_fe = subtree_on_left ? static_cast<double>(count_left)/sum_count : static_cast<double>(count_left)/sum_count;
		new_sibling.forced_extend = (1-ratio_fe) * node.forced_extend;
		node.forced_extend *= ratio_fe;
	}
	else if(fe_distribution == FE_DISTRIBUTION_DECREMENT){
		new_sibling.forced_extend = 0;
		node.forced_extend --;
	}
	new_parent.forced_extend = 0;

	int to_remove[label_count] = {0};
	//If subtree_on_left, then discharge on right
	adjust_counters(node_id, dimension, split_value, !subtree_on_left, to_remove);
	//Place the new counters in new_sibling
	for(int i = 0; i < label_count; ++i)
		new_sibling.counters[i] += to_remove[i];
	//Adjust the boxes' bound and reshape the tree is needed
	adjust_boxes(node_id, dimension, split_value, subtree_on_left, tree_id);

	//Propage the datapoint on the right side of the new split
	if(features[dimension] > split_value){
		pass_data_point_down(new_parent.child_right, features, label);
	}
	else{
		pass_data_point_down(new_parent.child_left, features, label);
	}
	return true;
}

// Assembly:
movl 0x38(%rdi), %eax
testl %eax, %eax
je 0x493c
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movl %r8d, %ebx
movq %rcx, %r14
movl %edx, %r12d
movq %rdi, %r15
movsd %xmm0, 0x18(%rsp)
movslq %esi, %rcx
shlq $0x7, %rcx
addq %rdi, %rcx
addq $0x44, %rcx
movq %rcx, 0x8(%rsp)
cmpl $0x2, %eax
movl %esi, 0x4(%rsp)
je 0x45a9
cmpl $0x1, %eax
jne 0x45d5
movupd 0x1820(%r15), %xmm0
unpcklpd %xmm0, %xmm0            # xmm0 = xmm0[0,0]
xorl %eax, %eax
movupd 0x1800(%r15,%rax,8), %xmm1
divpd %xmm0, %xmm1
movapd %xmm1, 0x80(%rsp,%rax,8)
addq $0x2, %rax
cmpq $0x4, %rax
jne 0x4586
jmp 0x45d5
movslq 0x17dc(%r15), %rax
imulq $-0x38, %rax, %rax
addq %r15, %rax
movslq %r12d, %rcx
imulq $0x38, %rcx, %rcx
movl 0x17bc(%rcx,%rax), %esi
leaq 0x80(%rsp), %rdx
movq %r15, %rdi
callq 0x53ca
leaq 0x44(%r15), %rbp
movq 0x8(%rsp), %rax
leaq 0x10(%rax), %rcx
leaq 0x30(%rax), %r13
xorpd %xmm0, %xmm0
xorl %eax, %eax
movapd 0x1a8c(%rip), %xmm1     # 0x6080
movsd 0x80(%rsp,%rax,8), %xmm2
ucomisd -0x20(%r13,%rax,8), %xmm2
jbe 0x4631
movsd (%r13,%rax,8), %xmm3
ucomisd %xmm2, %xmm3
jbe 0x4631
subsd (%r14,%rax,8), %xmm2
movapd %xmm2, %xmm3
xorpd %xmm1, %xmm3
maxsd %xmm2, %xmm3
movsd %xmm3, 0x40(%rsp,%rax,8)
addsd %xmm3, %xmm0
jmp 0x463a
movq $0x0, 0x40(%rsp,%rax,8)
incq %rax
cmpq $0x4, %rax
jne 0x45f4
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x4653
jnp 0x4935
ucomisd %xmm0, %xmm1
jbe 0x466e
xorpd %xmm0, %xmm0
xorl %eax, %eax
addsd 0x40(%rsp,%rax,8), %xmm0
incq %rax
cmpq $0x4, %rax
jne 0x465f
movsd 0x40(%rsp), %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, 0x40(%rsp)
movl $0x1, %eax
movsd 0x40(%rsp,%rax,8), %xmm2
divsd %xmm0, %xmm2
addsd %xmm2, %xmm1
movsd %xmm1, 0x40(%rsp,%rax,8)
incq %rax
cmpq $0x4, %rax
jne 0x4683
xorl %eax, %eax
xorpd %xmm0, %xmm0
movl %ebx, 0x34(%rsp)
movl %r12d, 0x20(%rsp)
movq %rcx, 0x70(%rsp)
movsd 0x40(%rsp,%rax,8), %xmm1
ucomisd %xmm0, %xmm1
jae 0x46ce
incq %rax
cmpq $0x4, %rax
jne 0x46b4
movl $0x4, %eax
cmpl $0x4, %eax
movl $0x4, %ecx
cmovll %eax, %ecx
movslq %ecx, %rax
movq %rax, 0x28(%rsp)
movsd 0x80(%rsp,%rax,8), %xmm2
movsd (%r14,%rax,8), %xmm0
movapd %xmm2, %xmm1
minsd %xmm0, %xmm1
maxsd %xmm0, %xmm2
subsd %xmm1, %xmm2
xorpd %xmm0, %xmm0
mulsd %xmm0, %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, 0x10(%rsp)
movq %r15, %rdi
callq 0x26e4
movl %eax, %ecx
movq 0x8(%rsp), %rax
movsd 0x60(%rax), %xmm0
movsd 0x18(%rsp), %xmm1
subsd %xmm1, %xmm0
mulsd 0x18e8(%rip), %xmm0     # 0x6020
addsd %xmm1, %xmm0
movl %ecx, 0x24(%rsp)
movslq %ecx, %r12
shlq $0x7, %r12
movq %rbp, %rbx
addq %r12, %rbp
movsd %xmm0, 0x60(%rbx,%r12)
movq %r15, %rdi
callq 0x26e4
movsd 0x17e8(%r15), %xmm0
movl %eax, 0x30(%rsp)
cltq
shlq $0x7, %rax
leaq (%rbx,%rax), %r8
leaq (%rbx,%rax), %rcx
addq $0x10, %rcx
movq %rcx, 0x60(%rsp)
movsd %xmm0, 0x50(%rcx)
addl $-0x2, 0x17d8(%r15)
movq 0x28(%rsp), %rcx
movl %ecx, (%rbx,%r12)
movsd 0x10(%rsp), %xmm0
movsd %xmm0, 0x8(%rbx,%r12)
leaq (%rbx,%rax), %r12
addq $0x30, %r12
xorl %eax, %eax
movsd -0x20(%r13,%rax), %xmm0
minsd (%r14,%rax), %xmm0
movsd %xmm0, 0x10(%rbp,%rax)
movsd (%r13,%rax), %xmm0
maxsd (%r14,%rax), %xmm0
movsd %xmm0, 0x30(%rbp,%rax)
movsd -0x20(%r13,%rax), %xmm0
movsd %xmm0, -0x20(%r12,%rax)
movsd (%r13,%rax), %xmm0
movsd %xmm0, (%r12,%rax)
addq $0x8, %rax
cmpq $0x20, %rax
jne 0x47ad
movq $0x0, 0x68(%r8)
movq 0x8(%rsp), %rax
movslq 0x58(%rax), %rax
cmpq $-0x1, %rax
movq %r15, 0x18(%rsp)
movq %r8, 0x68(%rsp)
jne 0x484e
movslq 0x17dc(%r15), %rcx
imulq $-0x38, %rcx, %rcx
addq %r15, %rcx
movslq 0x20(%rsp), %rdx
imulq $0x38, %rdx, %rdx
movl 0x4(%rsp), %esi
cmpl %esi, 0x17bc(%rdx,%rcx)
jne 0x484e
leaq (%rdx,%rcx), %rax
addq $0x17bc, %rax           # imm = 0x17BC
movl 0x4(%rsp), %r15d
jmp 0x486b
shlq $0x7, %rax
leaq (%rbx,%rax), %rcx
addq $0x50, %rcx
movl 0x4(%rsp), %r15d
cmpl %r15d, (%rcx)
leaq 0x54(%rbx,%rax), %rax
cmoveq %rcx, %rax
movl 0x24(%rsp), %ecx
movl %ecx, (%rax)
xorl %eax, %eax
leaq 0x3c(%rsp), %rcx
movl %eax, (%rcx)
leaq 0x38(%rsp), %r8
movl %eax, (%r8)
movq 0x18(%rsp), %rdi
movl %r15d, %esi
movq 0x28(%rsp), %rbx
movl %ebx, %edx
movsd 0x10(%rsp), %xmm0
callq 0x4a68
leaq 0x3c(%rsp), %rax
movl (%rax), %eax
leaq 0x38(%rsp), %rcx
movl (%rcx), %edx
cmpl %edx, %eax
movq 0x70(%rsp), %rsi
cmovgq %r13, %rsi
cmovgq 0x60(%rsp), %r12
movl %r15d, %ecx
movl 0x30(%rsp), %edi
cmovgl %edi, %ecx
cmovgl %r15d, %edi
movsd 0x10(%rsp), %xmm0
movsd %xmm0, (%rsi,%rbx,8)
movsd %xmm0, (%r12,%rbx,8)
movl %ecx, 0x54(%rbp)
movl %edi, 0x50(%rbp)
movq 0x8(%rsp), %rsi
movl 0x58(%rsi), %ecx
movl %ecx, 0x58(%rbp)
movl 0x24(%rsp), %ecx
movl %ecx, 0x58(%rsi)
movq 0x68(%rsp), %r12
movl %ecx, 0x58(%r12)
movq 0x18(%rsp), %rcx
movl 0x14(%rcx), %ecx
cmpq $0x3, %rcx
movl %r15d, %r9d
ja 0x49b9
leaq 0x17d0(%rip), %rsi      # 0x60e8
movslq (%rsi,%rcx,4), %rcx
addq %rsi, %rcx
jmpq *%rcx
xorl %ecx, %ecx
movq 0x8(%rsp), %rsi
movl %ecx, 0x70(%rsi)
movl %ecx, 0x70(%r12)
jmp 0x49b9
xorl %eax, %eax
jmp 0x4a56
xorl %eax, %eax
retq
leal (%rdx,%rax), %ecx
xorps %xmm0, %xmm0
cvtsi2sd %ecx, %xmm0
cvtsi2sd %eax, %xmm1
divsd %xmm0, %xmm1
movsd 0x16bf(%rip), %xmm0     # 0x6018
movq 0x8(%rsp), %rsi
cvtsi2sdl 0x70(%rsi), %xmm2
subsd %xmm1, %xmm0
mulsd %xmm0, %xmm2
cvttsd2si %xmm2, %ecx
jmp 0x49a1
movl $0x0, 0x70(%r12)
movq 0x8(%rsp), %rcx
decl 0x70(%rcx)
jmp 0x49b9
movq 0x8(%rsp), %rsi
xorps %xmm0, %xmm0
cvtsi2sdl 0x70(%rsi), %xmm0
movsd 0x169f(%rip), %xmm1     # 0x6038
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %ecx
movl %ecx, 0x70(%r12)
xorps %xmm0, %xmm0
cvtsi2sdl 0x70(%rsi), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %ecx
movl %ecx, 0x70(%rsi)
xorl %ebx, %ebx
xorl %ecx, %ecx
cmpl %edx, %eax
setg %bl
setle %cl
movl $0x0, 0x70(%rbp)
leaq 0x78(%rsp), %rax
movq $0x0, (%rax)
movq 0x18(%rsp), %r15
movq %r15, %rdi
movl %r9d, %esi
movq 0x28(%rsp), %r13
movl %r13d, %edx
movsd 0x10(%rsp), %xmm0
movq %rax, %r8
callq 0x4c12
leaq 0x78(%rsp), %rax
movq (%rax), %xmm0
movq 0x68(%r12), %xmm1
paddd %xmm0, %xmm1
movq %xmm1, 0x68(%r12)
movq %r15, %rdi
movl 0x4(%rsp), %esi
movl %r13d, %edx
movsd 0x10(%rsp), %xmm0
movl %ebx, %ecx
movl 0x20(%rsp), %r8d
callq 0x4eca
movsd (%r14,%r13,8), %xmm0
xorl %eax, %eax
ucomisd 0x10(%rsp), %xmm0
seta %al
movl 0x50(%rbp,%rax,4), %esi
movq %r15, %rdi
movq %r14, %rdx
movl 0x34(%rsp), %ecx
callq 0x534a
movb $0x1, %al
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq