// 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>::extend_block0(int, int, double const*, int)
void extend_block0(int const node_id, int const tree_id, feature_type const* features, int const label){
	//e_lower and e_upper are used to compute probabilities
	feature_type e_lower[feature_count], e_upper[feature_count];
	double probabilities[feature_count];
	Node& node = nodes()[node_id];
	int const parent_id = node.parent;
	double const parent_tau = node.parent >= 0 ? nodes()[node.parent].tau : 0; //The tau value of the parent of the root is 0
	//sum is used as a parameter to pick random numbers following exponential law
	feature_type sum = 0;
	//compute e_lower, e_upper and sum
	for(int i = 0; i < feature_count; ++i){
		e_lower[i] = node.bound_lower[i] - features[i] > 0 ? node.bound_lower[i] - features[i] : 0;
		e_upper[i] = features[i] - node.bound_upper[i] > 0 ? features[i] - node.bound_upper[i] : 0;
		probabilities[i] = e_lower[i] + e_upper[i];
		sum += e_lower[i] + e_upper[i];
	}
	//Pick a random number following an exponential law of parameter *sum* (except if sum is 0)
	double const E = sum == 0 ?  -1 : Utils::rand_exponential<func>(sum);
	bool update_box = false;

	bool pause_expension = false;
	if((tree_management == COBBLE_MANAGEMENT || tree_management == OPTIMISTIC_COBBLE_MANAGEMENT)){
		int const remaining_depth = node_depth(node_id, nullptr);
		int const distance_to_root = unravel(node_id);
		pause_expension = remaining_depth + distance_to_root + 1 > tree_bases()[tree_id].node_count_limit;
	}
	else{
		pause_expension = tree_bases()[tree_id].is_paused(tree_management);
		//PAUSE
		//pause_expension = ((total_count >= 20 && total_count <= 150));
	}

	if(E >= 0 && parent_tau + E < node.tau && node_available >= 2 && !pause_expension){//Introduce a new parent and a new sibling
		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, upper_value;
		if(features[dimension] > node.bound_upper[dimension]){
			lower_value = node.bound_upper[dimension];
			upper_value = features[dimension];
		}
		else if(features[dimension] < node.bound_lower[dimension]){
			lower_value = features[dimension];
			upper_value = node.bound_lower[dimension];
		}

		//sample the split between [lower_value, upper_value]
		double const split_value = func::rand_uniform()*(upper_value - lower_value) + lower_value;
		int new_parent, new_sibling;
		//insert new node above the current one
		new_parent = available_node();
		nodes()[new_parent].split_dimension = dimension;
		nodes()[new_parent].split_value = split_value;
		nodes()[new_parent].tau = parent_tau + E;
		//insert new leaf, sibbling of the current one
		new_sibling = available_node();
		node_available -= 2;

		//Update the box of the new parent
		for(int i = 0; i < feature_count; ++i){
			nodes()[new_parent].bound_lower[i] = features[i] < node.bound_lower[i] ? features[i] : node.bound_lower[i];
			nodes()[new_parent].bound_upper[i] = features[i] > node.bound_upper[i] ? features[i] : node.bound_upper[i];
		}
		//NOTE Creates counters for the label of the new parent
		for(int i = 0; i < label_count; ++i)
			nodes()[new_parent].counters[i] = Utils::min(1, node.counters[i]);

		//Creates counters for the label of the new sibling
		for(int i = 0; i < label_count; ++i)
			nodes()[new_sibling].counters[i] = 0;
		//No need to increase the counter for the current label because we will call sample_block soon on new_sibling

		//Make the connections between the new nodes
		nodes()[new_parent].parent = node.parent;
		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;
		else{
			Node& parent = nodes()[node.parent];
			if(parent.child_left == node_id)
				parent.child_left = new_parent;
			else
				parent.child_right = new_parent;
		}


		node.parent = new_parent;

		nodes()[new_sibling].parent = new_parent;
		if(features[dimension] == upper_value){ //right
			nodes()[new_parent].child_right = new_sibling;
			nodes()[new_parent].child_left = node_id;
		}
		else{ //left
			nodes()[new_parent].child_left = new_sibling;
			nodes()[new_parent].child_right = node_id;
		}
		//cout << "Split dimension " << dimension << " on " << split_value << "(total count: " << total_count << ")" << endl;

		sample_block(new_sibling, features, label);
	}
	else{ //Otherwise, just update the box
		//update lower bound and upper bound of this node
		for(int i = 0; i < feature_count; ++i){
			if(node.bound_lower[i] > features[i])
				node.bound_lower[i] = features[i];
			if(node.bound_upper[i] < features[i])
				node.bound_upper[i] = features[i];
		}
		//if not leaf, recurse on the node that contains the data point
		if(!node.is_leaf()){
			if(features[node.split_dimension] <= node.split_value)
				extend_block0(node.child_left, tree_id, features, label);
			else if(features[node.split_dimension] > node.split_value)
				extend_block0(node.child_right, tree_id, features, label);
			//NOTE: we don't update the counters of labels here because the counting will be done when prediction is required.
			//We can optimize that.
		}
		else{
			//Update the counter of label
			node.counters[label] += 1;
			node.fading_score += 1; //fading_score is decreased later on
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rcx, %r14
movq %rdi, %r15
leaq 0x44(%rdi), %rbp
movslq %esi, %rax
shlq $0x7, %rax
movslq 0x9c(%rdi,%rax), %rcx
xorpd %xmm4, %xmm4
xorpd %xmm3, %xmm3
testq %rcx, %rcx
js 0x27d8
shlq $0x7, %rcx
movsd 0x60(%rbp,%rcx), %xmm3
leaq (%r15,%rax), %rbx
addq $0x44, %rbx
xorl %eax, %eax
xorpd %xmm0, %xmm0
movsd (%r14,%rax,8), %xmm1
movsd 0x10(%rbx,%rax,8), %xmm2
unpcklpd %xmm1, %xmm2            # xmm2 = xmm2[0],xmm1[0]
movhpd 0x30(%rbx,%rax,8), %xmm1 # xmm1 = xmm1[0],mem[0]
subpd %xmm1, %xmm2
maxpd %xmm0, %xmm2
movapd %xmm2, %xmm1
unpckhpd %xmm2, %xmm1            # xmm1 = xmm1[1],xmm2[1]
addsd %xmm2, %xmm1
movsd %xmm1, 0x50(%rsp,%rax,8)
addsd %xmm1, %xmm4
incq %rax
cmpq $0x4, %rax
jne 0x27e6
movsd 0x37fd(%rip), %xmm0     # 0x6028
divsd %xmm4, %xmm0
xorpd %xmm1, %xmm1
cmpeqsd %xmm4, %xmm1
movsd 0x37f0(%rip), %xmm2     # 0x6030
andpd %xmm1, %xmm2
andnpd %xmm0, %xmm1
orpd %xmm1, %xmm2
movl (%r15), %eax
cmpl $0x2, %eax
jae 0x28e0
movapd %xmm2, 0x30(%rsp)
movsd %xmm4, 0x10(%rsp)
movsd %xmm3, 0x18(%rsp)
movl %r8d, 0xc(%rsp)
movl %edx, %r13d
movq %r15, %rdi
xorl %edx, %edx
movl %esi, %r12d
callq 0x3dce
movl %r12d, %esi
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpl %r12d, 0x17d4(%r15)
jle 0x28a4
movl %esi, %edx
movslq %edx, %rdx
shlq $0x7, %rdx
movl 0x58(%rbp,%rdx), %edx
incl %ecx
cmpl $-0x1, %edx
jne 0x2892
addl %eax, %ecx
movslq 0x17dc(%r15), %rax
imulq $-0x38, %rax, %rax
addq %r15, %rax
movl %r13d, %edx
movslq %r13d, %rdi
imulq $0x38, %rdi, %rdi
addq %rdi, %rax
addq $0x17b4, %rax           # imm = 0x17B4
movl 0xc(%rsp), %r8d
movsd 0x18(%rsp), %xmm3
movsd 0x10(%rsp), %xmm4
movapd 0x30(%rsp), %xmm2
jmp 0x290f
cmpl $0x4, %eax
je 0x28ee
cmpl $0x2, %eax
jne 0x29dd
movslq 0x17dc(%r15), %rax
imulq $-0x38, %rax, %rax
addq %r15, %rax
movslq %edx, %rcx
imulq $0x38, %rcx, %rcx
addq %rcx, %rax
addq $0x17b4, %rax           # imm = 0x17B4
movl 0x4(%rax), %ecx
cmpl (%rax), %ecx
setge %al
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm2
jb 0x2943
addsd %xmm2, %xmm3
movsd 0x60(%rbx), %xmm0
ucomisd %xmm3, %xmm0
jbe 0x2943
cmpl $0x2, 0x17d8(%r15)
setl %cl
orb %al, %cl
testb $0x1, %cl
je 0x29e4
xorl %eax, %eax
movsd 0x10(%rbx,%rax,8), %xmm1
movsd (%r14,%rax,8), %xmm0
ucomisd %xmm0, %xmm1
jbe 0x2963
movsd %xmm0, 0x10(%rbx,%rax,8)
movsd (%r14,%rax,8), %xmm0
ucomisd 0x30(%rbx,%rax,8), %xmm0
jbe 0x2971
movsd %xmm0, 0x30(%rbx,%rax,8)
incq %rax
cmpq $0x4, %rax
jne 0x2945
movslq (%rbx), %rax
cmpq $-0x1, %rax
je 0x29a3
movsd (%r14,%rax,8), %xmm0
movsd 0x8(%rbx), %xmm1
ucomisd %xmm0, %xmm1
jae 0x29c1
ucomisd %xmm1, %xmm0
jbe 0x2c41
movl 0x54(%rbx), %esi
jmp 0x29c4
movslq %r8d, %rax
incl 0x68(%rbx,%rax,4)
movsd 0x78(%rbx), %xmm0
addsd 0x3661(%rip), %xmm0     # 0x6018
movsd %xmm0, 0x78(%rbx)
jmp 0x2c41
movl 0x50(%rbx), %esi
movq %r15, %rdi
movq %r14, %rcx
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x279a
xorl %eax, %eax
jmp 0x2914
xorpd %xmm0, %xmm0
ucomisd %xmm4, %xmm0
jbe 0x2a03
xorl %eax, %eax
xorpd %xmm4, %xmm4
addsd 0x50(%rsp,%rax,8), %xmm4
incq %rax
cmpq $0x4, %rax
jne 0x29f4
movsd 0x50(%rsp), %xmm0
divsd %xmm4, %xmm0
movsd %xmm0, 0x50(%rsp)
movl $0x1, %eax
movsd 0x50(%rsp,%rax,8), %xmm1
divsd %xmm4, %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, 0x50(%rsp,%rax,8)
incq %rax
cmpq $0x4, %rax
jne 0x2a18
xorl %eax, %eax
xorpd %xmm0, %xmm0
movsd 0x50(%rsp,%rax,8), %xmm1
ucomisd %xmm0, %xmm1
jae 0x2a55
incq %rax
cmpq $0x4, %rax
jne 0x2a3b
movl $0x4, %eax
cmpl $0x4, %eax
movl $0x4, %ecx
cmovll %eax, %ecx
movl %ecx, %r12d
movslq %ecx, %rax
movsd (%r14,%rax,8), %xmm0
movsd 0x30(%rbx,%rax,8), %xmm1
ucomisd %xmm1, %xmm0
movl %r8d, 0xc(%rsp)
movl %edx, 0x2c(%rsp)
movsd %xmm3, 0x18(%rsp)
movq %rax, 0x10(%rsp)
movl %esi, 0x24(%rsp)
jbe 0x2a9a
movapd %xmm0, %xmm2
movapd %xmm1, %xmm0
jmp 0x2aa0
movsd 0x10(%rbx,%rax,8), %xmm2
movsd %xmm2, 0x30(%rsp)
movapd %xmm2, %xmm1
subsd %xmm0, %xmm1
xorpd %xmm2, %xmm2
mulsd %xmm1, %xmm2
addsd %xmm0, %xmm2
movsd %xmm2, 0x48(%rsp)
movq %r15, %rdi
callq 0x26e4
movl %eax, 0x28(%rsp)
movslq %eax, %r13
shlq $0x7, %r13
movl %r12d, (%rbp,%r13)
movsd 0x48(%rsp), %xmm0
movsd %xmm0, 0x8(%rbp,%r13)
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x60(%rbp,%r13)
movq %r15, %rdi
callq 0x26e4
addl $-0x2, 0x17d8(%r15)
leaq (%r15,%r13), %rcx
addq $0x74, %rcx
xorl %edx, %edx
movsd (%r14,%rdx,8), %xmm0
minsd 0x10(%rbx,%rdx,8), %xmm0
movsd %xmm0, -0x20(%rcx,%rdx,8)
movsd (%r14,%rdx,8), %xmm0
maxsd 0x30(%rbx,%rdx,8), %xmm0
movsd %xmm0, (%rcx,%rdx,8)
incq %rdx
cmpq $0x4, %rdx
jne 0x2b0c
movq 0x68(%rbx), %xmm0
movdqa 0x354b(%rip), %xmm1     # 0x6090
movdqa %xmm1, %xmm2
pcmpgtd %xmm0, %xmm2
pand %xmm2, %xmm0
pandn %xmm1, %xmm2
por %xmm0, %xmm2
movq %xmm2, 0x68(%rbp,%r13)
movslq %eax, %rcx
shlq $0x7, %rcx
movq $0x0, 0xac(%r15,%rcx)
movslq 0x58(%rbx), %rdx
movl %edx, 0x58(%rbp,%r13)
cmpq $-0x1, %rdx
movl 0x2c(%rsp), %edi
movl 0x24(%rsp), %r12d
jne 0x2bb7
movslq 0x17dc(%r15), %rsi
imulq $-0x38, %rsi, %rsi
addq %r15, %rsi
movslq %edi, %rdi
imulq $0x38, %rdi, %rdi
cmpl %r12d, 0x17bc(%rdi,%rsi)
jne 0x2bb7
leaq (%rdi,%rsi), %rdx
addq $0x17bc, %rdx           # imm = 0x17BC
jmp 0x2bcf
shlq $0x7, %rdx
leaq (%rdx,%rbp), %rsi
addq $0x50, %rsi
cmpl %r12d, (%rsi)
leaq 0x54(%rbp,%rdx), %rdx
cmoveq %rsi, %rdx
movsd 0x30(%rsp), %xmm0
movl 0x28(%rsp), %esi
movl %esi, (%rdx)
movl %esi, 0x58(%rbx)
movl %esi, 0x58(%rbp,%rcx)
movq 0x10(%rsp), %rdx
ucomisd (%r14,%rdx,8), %xmm0
movl %eax, %edx
cmovnel %r12d, %edx
cmovpl %r12d, %edx
cmovnel %eax, %r12d
cmovpl %eax, %r12d
leaq (%rcx,%rbp), %rax
movl %edx, 0x54(%rbp,%r13)
movl %r12d, 0x50(%rbp,%r13)
xorl %ecx, %ecx
movsd (%r14,%rcx,8), %xmm0
movsd %xmm0, 0x10(%rax,%rcx,8)
movsd %xmm0, 0x30(%rax,%rcx,8)
incq %rcx
cmpq $0x4, %rcx
jne 0x2c0f
movslq 0xc(%rsp), %rcx
incl 0x68(%rax,%rcx,4)
movsd 0x17e8(%r15), %xmm0
movsd %xmm0, 0x60(%rax)
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq