// File: /workspace/github_cpp_makefile_star2_O1/big-data-lab-team[P]OrpailleCC/./src/mondrian_coarse.hpp
// Function: CoarseMondrianForest<double, funct, KappaMetrics<2, false>, 4, 2, 6000>::predict_tree(double const*, int, double*, int) const
void predict_tree(feature_type const* features, int const tree_id, double* posterior_means, int const depth_limit = -1) const{
	int node_id = tree_bases()[tree_id].root;
	int depth = 0;
	for(int i = 0; i < label_count; ++i)
		posterior_means[i] = base_measure;

	if(node_id == -1) //The tree is empty. just return.
		return;
	double pp_sum = 0, pp_mul = 1;
	double probability_of_branching;
	double probability_not_separated_yet = 1;
	double parent_tau = 0;

	double smoothed_posterior_means[label_count] = {0};

	//Find the corresponding leaf for the data point
	while(node_id >= 0 && node_id < node_count) {
		Node const& current_node = nodes()[node_id];

		double const delta_tau = current_node.tau - parent_tau;
		double eta = 0;
		for(int i = 0; i < feature_count; ++i)
			eta += Utils::max(features[i] - current_node.bound_upper[i], 0.0) + Utils::max(current_node.bound_lower[i] - features[i], 0.0);

		probability_of_branching = 1 - func::exp(-delta_tau * eta);

		if(probability_of_branching > 0){
			double const new_node_discount = (eta / (eta + discount_factor)) *
											-Utils::expm1<func>(-(eta + discount_factor) * delta_tau) / -Utils::expm1<func>(-(eta * delta_tau));
			double c[label_count];
			double c_sum = 0;
			//We need the sum of *c*, so we need two loops
			for(int l = 0; l < label_count; ++l){
				c[l] = Utils::min(current_node.counters[l], 1);
				c_sum += c[l];
			}

			for(int l = 0; l < label_count; ++l){
				//posterior_means of the parent of current_node
				double const posterior_mean = (1/c_sum) * (c[l] - new_node_discount * c[l] + c_sum * posterior_means[l]);
				//Note that *posterior_mean* is the value for the hypothetical parent
				smoothed_posterior_means[l] += probability_not_separated_yet * probability_of_branching * posterior_mean;
			}
		}

		//NOTE: *posterior_means* cannot be update before we need the parent value above
		compute_posterior_mean(current_node, posterior_means);

		//If we reach a leaf, and *posterior_means* will be set to the value for this leaf.
		bool too_deep = (depth+1 >= depth_limit) && (depth_limit >= 0);
		if(too_deep || current_node.is_leaf()){
			for(int l = 0; l < label_count; ++l)
				posterior_means[l] = smoothed_posterior_means[l] + probability_not_separated_yet * (1 - probability_of_branching) * posterior_means[l];
			break;
		}
		probability_not_separated_yet *= (1 - probability_of_branching);

		//Otherwise, the child is picked based on the split of the node
		if(features[current_node.split_dimension] <= current_node.split_value)
			node_id = current_node.child_left;
		else
			node_id = current_node.child_right;
		depth += 1;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movl %r8d, (%rsp)
movq %rcx, %r14
movq %rsi, %r15
movslq 0x17dc(%rdi), %rax
imulq $-0x38, %rax, %rax
addq %rdi, %rax
movslq %edx, %rcx
imulq $0x38, %rcx, %rcx
movl 0x17bc(%rcx,%rax), %edx
xorl %eax, %eax
movsd 0x17f0(%rdi), %xmm0
movsd %xmm0, (%r14,%rax,8)
incq %rax
cmpq $0x1, %rax
je 0x1d12
cmpl $-0x1, %edx
je 0x1efc
xorpd %xmm0, %xmm0
movapd %xmm0, 0x20(%rsp)
leaq 0x44(%rdi), %rax
movq %rax, 0x38(%rsp)
movq $0x0, 0x10(%rsp)
movsd 0x42c2(%rip), %xmm5     # 0x6018
xorpd %xmm3, %xmm3
movl $0x1, %ebx
movq %rdi, 0x8(%rsp)
movl (%rsp), %r12d
testl %edx, %edx
js 0x1efc
cmpl 0x17d4(%rdi), %edx
jge 0x1efc
movl %edx, %r13d
shlq $0x7, %r13
addq 0x38(%rsp), %r13
xorpd %xmm0, %xmm0
xorl %eax, %eax
movsd (%r15,%rax,8), %xmm1
movsd 0x10(%r13,%rax,8), %xmm2
subsd %xmm1, %xmm2
subsd 0x30(%r13,%rax,8), %xmm1
maxsd %xmm3, %xmm1
maxsd %xmm3, %xmm2
addsd %xmm1, %xmm2
addsd %xmm2, %xmm0
incq %rax
cmpq $0x4, %rax
jne 0x1d8e
movsd 0x17f8(%rdi), %xmm2
addsd %xmm0, %xmm2
xorpd %xmm1, %xmm1
xorl %eax, %eax
movl 0x68(%r13,%rax,4), %ecx
testl %ecx, %ecx
cmovgl %ebx, %ecx
xorps %xmm3, %xmm3
cvtsi2sd %ecx, %xmm3
movsd %xmm3, 0x40(%rsp,%rax,8)
addsd %xmm3, %xmm1
incq %rax
cmpq $0x1, %rax
je 0x1dd1
movl %edx, 0x4(%rsp)
xorpd 0x425f(%rip), %xmm0     # 0x6060
movsd 0x420f(%rip), %xmm3     # 0x6018
divsd %xmm1, %xmm3
divsd %xmm2, %xmm0
xorl %eax, %eax
movsd 0x40(%rsp,%rax,8), %xmm2
movapd %xmm0, %xmm4
mulsd %xmm2, %xmm4
addsd %xmm2, %xmm4
movsd (%r14,%rax,8), %xmm2
mulsd %xmm1, %xmm2
addsd %xmm4, %xmm2
mulsd %xmm3, %xmm2
mulsd %xmm5, %xmm2
addsd 0x20(%rsp,%rax,8), %xmm2
movsd %xmm2, 0x20(%rsp,%rax,8)
incq %rax
cmpq $0x1, %rax
je 0x1e13
movsd %xmm5, 0x18(%rsp)
testl %r12d, %r12d
setns %bpl
movq %r13, %rsi
movq %r14, %rdx
callq 0x1f86
movq 0x10(%rsp), %rax
incl %eax
cmpl %r12d, %eax
setge %cl
testb %cl, %bpl
jne 0x1eb6
movslq (%r13), %rcx
cmpq $-0x1, %rcx
je 0x1eb6
xorpd %xmm3, %xmm3
movsd 0x18(%rsp), %xmm5
mulsd %xmm3, %xmm5
movsd 0x8(%r13), %xmm0
xorl %edx, %edx
ucomisd (%r15,%rcx,8), %xmm0
setb %dl
movl 0x50(%r13,%rdx,4), %edx
movb $0x1, %cl
movq %rax, 0x10(%rsp)
movq 0x8(%rsp), %rdi
jmp 0x1ef4
movsd 0x18(%rsp), %xmm5
movapd %xmm5, %xmm0
xorpd %xmm3, %xmm3
mulsd %xmm3, %xmm0
xorl %eax, %eax
movsd (%r14,%rax,8), %xmm1
mulsd %xmm0, %xmm1
addsd 0x20(%rsp,%rax,8), %xmm1
movsd %xmm1, (%r14,%rax,8)
incq %rax
cmpq $0x1, %rax
je 0x1eca
xorl %ecx, %ecx
movq 0x8(%rsp), %rdi
movl 0x4(%rsp), %edx
testb %cl, %cl
jne 0x1d68
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop