// 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_block4(int, int, double const*, int, int)
void extend_block4(int const node_id, int const tree_id, feature_type const* features, int const label, int const forced_extend_sum=0){
	//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
		bool split_instead = false;
		//If forced_extend_sum is higher than 0, then we consider spliting
		if(forced_extend_sum > 0){
			double const probability = static_cast<double>(node.forced_extend) / static_cast<double>(forced_extend_sum);
			split_instead = (func::rand_uniform() <  probability);
		}

		if(fe_split_trigger == SPLIT_TRIGGER_NONE){
			extend_node(node_id, tree_id, features, label, parent_id, parent_tau, probabilities, E, sum);
		}
		else if(fe_split_trigger == SPLIT_TRIGGER_POSITIVE && node.forced_extend > 0){
			split_node(node_id, tree_id, features, label, parent_id, parent_tau, probabilities, E);
		}
		else if((fe_split_trigger == SPLIT_TRIGGER_TOTAL || fe_split_trigger == SPLIT_TRIGGER_SFE) && split_instead){
			split_node(node_id, tree_id, features, label, parent_id, parent_tau, probabilities, E);
		}
		else{
			extend_node(node_id, tree_id, features, label, parent_id, parent_tau, probabilities, E, sum);
		}
	}
	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]){
				double const difference = (node.bound_lower[i] - features[i]) * fe_parameter;
				node.bound_lower[i] -= difference;
			}
			if(node.bound_upper[i] < features[i]){
				double const difference = (features[i] - node.bound_upper[i]) * fe_parameter;
				node.bound_upper[i] += difference;
			}
		}
		//Check if it's a forced extend
		if(E >= 0 && (parent_tau + E < node.tau)){
			node.forced_extend += 1;
		}
		//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_block4(node.child_left, tree_id, features, label, forced_extend_sum);
			else if(features[node.split_dimension] > node.split_value)
				extend_block4(node.child_right, tree_id, features, label, forced_extend_sum);
			//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{
			bool has_split_bary = false;
			//PAUSE
			//if(!((total_count >= 20 && total_count <= 150)) && E < 0 && node_available >= 2){//Data point in the box
			if(has_been_full > 20 && E < 0 && node_available >= 2){//Data point in the box
					has_split_bary = split_barycenter(node_id, tree_id, features, label, parent_id, parent_tau);
			}
			if(!has_split_bary){

				//Update the counter of label
				node.counters[label] += 1;
				node.fading_score += 1; //fading_score is decreased later
			}
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movl %r9d, %r10d
movq %rcx, %r14
movq %rdi, %r12
leaq 0x44(%rdi), %rbp
movslq %esi, %rax
shlq $0x7, %rax
movslq 0x9c(%rdi,%rax), %r9
xorpd %xmm2, %xmm2
xorpd %xmm0, %xmm0
testq %r9, %r9
js 0x3a88
movq %r9, %rcx
shlq $0x7, %rcx
movsd 0x60(%rbp,%rcx), %xmm0
leaq (%r12,%rax), %rbx
addq $0x44, %rbx
xorl %eax, %eax
xorpd %xmm3, %xmm3
movsd (%r14,%rax,8), %xmm1
movsd 0x10(%rbx,%rax,8), %xmm4
unpcklpd %xmm1, %xmm4            # xmm4 = xmm4[0],xmm1[0]
movhpd 0x30(%rbx,%rax,8), %xmm1 # xmm1 = xmm1[0],mem[0]
subpd %xmm1, %xmm4
maxpd %xmm3, %xmm4
movapd %xmm4, %xmm1
unpckhpd %xmm4, %xmm1            # xmm1 = xmm1[1],xmm4[1]
addsd %xmm4, %xmm1
movsd %xmm1, 0x30(%rsp,%rax,8)
addsd %xmm1, %xmm2
incq %rax
cmpq $0x4, %rax
jne 0x3a96
movsd 0x254d(%rip), %xmm3     # 0x6028
divsd %xmm2, %xmm3
xorpd %xmm1, %xmm1
cmpeqsd %xmm2, %xmm1
movsd 0x2540(%rip), %xmm4     # 0x6030
andpd %xmm1, %xmm4
andnpd %xmm3, %xmm1
orpd %xmm1, %xmm4
movl (%r12), %eax
cmpl $0x2, %eax
jae 0x3ba7
movsd %xmm2, 0x18(%rsp)
movapd %xmm4, 0x50(%rsp)
movl %r10d, 0x10(%rsp)
movsd %xmm0, 0x20(%rsp)
movq %r9, 0x28(%rsp)
movl %edx, %r13d
movl %r8d, 0x14(%rsp)
movq %r12, %rdi
xorl %edx, %edx
movl %esi, %r15d
callq 0x3dce
movl %r15d, %esi
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
cmpl %r15d, 0x17d4(%r12)
jle 0x3b60
movl %esi, %edx
movslq %edx, %rdx
shlq $0x7, %rdx
movl 0x58(%rbp,%rdx), %edx
incl %ecx
cmpl $-0x1, %edx
jne 0x3b4e
addl %eax, %ecx
movslq 0x17dc(%r12), %rax
imulq $-0x38, %rax, %rax
addq %r12, %rax
movl %r13d, %edx
movslq %r13d, %rdi
imulq $0x38, %rdi, %rdi
addq %rdi, %rax
addq $0x17b4, %rax           # imm = 0x17B4
movl 0x14(%rsp), %r8d
movq 0x28(%rsp), %r9
movsd 0x20(%rsp), %xmm0
movl 0x10(%rsp), %r10d
movapd 0x50(%rsp), %xmm4
movsd 0x18(%rsp), %xmm2
jmp 0x3bd7
cmpl $0x4, %eax
je 0x3bb5
cmpl $0x2, %eax
jne 0x3d60
movslq 0x17dc(%r12), %rax
imulq $-0x38, %rax, %rax
addq %r12, %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 %xmm1, %xmm1
ucomisd %xmm1, %xmm4
jb 0x3c17
movapd %xmm0, %xmm3
addsd %xmm4, %xmm3
movsd 0x60(%rbx), %xmm1
ucomisd %xmm3, %xmm1
setbe %cl
cmpl $0x2, 0x17d8(%r12)
setl %dil
orb %cl, %dil
orb %al, %dil
testb $0x1, %dil
je 0x3d1b
xorl %eax, %eax
movsd 0x10(%rbx,%rax,8), %xmm1
movsd (%r14,%rax,8), %xmm3
ucomisd %xmm3, %xmm1
jbe 0x3c4a
movapd %xmm1, %xmm2
subsd %xmm3, %xmm2
mulsd 0x30(%r12), %xmm2
subsd %xmm2, %xmm1
movsd %xmm1, 0x10(%rbx,%rax,8)
movsd (%r14,%rax,8), %xmm3
movsd 0x30(%rbx,%rax,8), %xmm1
ucomisd %xmm1, %xmm3
jbe 0x3c6b
subsd %xmm1, %xmm3
mulsd 0x30(%r12), %xmm3
addsd %xmm1, %xmm3
movsd %xmm3, 0x30(%rbx,%rax,8)
incq %rax
cmpq $0x4, %rax
jne 0x3c19
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm4
jb 0x3c94
movapd %xmm0, %xmm2
addsd %xmm4, %xmm2
movsd 0x60(%rbx), %xmm1
ucomisd %xmm2, %xmm1
jbe 0x3c94
incl 0x70(%rbx)
movslq (%rbx), %rax
cmpq $-0x1, %rax
je 0x3cc4
movsd (%r14,%rax,8), %xmm0
movsd 0x8(%rbx), %xmm1
ucomisd %xmm0, %xmm1
jae 0x3d41
ucomisd %xmm1, %xmm0
jbe 0x3dbf
movl 0x54(%rbx), %esi
jmp 0x3d44
xorpd %xmm1, %xmm1
ucomisd %xmm4, %xmm1
jbe 0x3cfd
cmpl $0x15, 0x1840(%r12)
jl 0x3cfd
cmpl $0x2, 0x17d8(%r12)
jl 0x3cfd
movq %r12, %rdi
movq %r14, %rcx
movl %r8d, %ebp
callq 0x4528
movl %ebp, %r8d
testb %al, %al
jne 0x3dbf
movslq %r8d, %rax
incl 0x68(%rbx,%rax,4)
movsd 0x78(%rbx), %xmm0
addsd 0x2307(%rip), %xmm0     # 0x6018
movsd %xmm0, 0x78(%rbx)
jmp 0x3dbf
testl %r10d, %r10d
jle 0x3d67
xorps %xmm3, %xmm3
cvtsi2sdl 0x70(%rbx), %xmm3
xorps %xmm1, %xmm1
cvtsi2sd %r10d, %xmm1
divsd %xmm1, %xmm3
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm3
setbe %al
jmp 0x3d69
movl 0x50(%rbx), %esi
movq %r12, %rdi
movq %r14, %rcx
movl %r10d, %r9d
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3a44
xorl %eax, %eax
jmp 0x3bdc
movb $0x1, %al
movl 0x18(%r12), %ecx
cmpl $0x1, %ecx
je 0x3da1
testl %ecx, %ecx
je 0x3d87
andl $-0x2, %ecx
cmpl $0x2, %ecx
setne %cl
orb %al, %cl
testb $0x1, %cl
je 0x3da7
leaq 0x30(%rsp), %rax
movq %rax, (%rsp)
movq %r12, %rdi
movq %r14, %rcx
movapd %xmm4, %xmm1
callq 0x3e94
jmp 0x3dbf
cmpl $0x0, 0x70(%rbx)
jle 0x3d87
leaq 0x30(%rsp), %rax
movq %rax, (%rsp)
movq %r12, %rdi
movq %r14, %rcx
movapd %xmm4, %xmm1
callq 0x4108
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq