// File: /workspace/github_cpp_makefile_star2_O2/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 $0x48, %rsp
movl %r8d, 0x4(%rsp)
movq %rcx, %rbx
movq %rsi, %r14
movq %rdi, %r15
movslq 0x17dc(%rdi), %rax
imulq $-0x38, %rax, %rax
addq %rdi, %rax
movslq %edx, %rcx
imulq $0x38, %rcx, %rcx
movl 0x17bc(%rcx,%rax), %eax
xorl %ecx, %ecx
cmpq $0x2, %rcx
je 0x1bef
movsd 0x17f0(%r15), %xmm0
movsd %xmm0, (%rbx,%rcx,8)
incq %rcx
jmp 0x1bd6
cmpl $-0x1, %eax
je 0x1d91
xorpd %xmm4, %xmm4
movapd %xmm4, 0x10(%rsp)
leaq 0x44(%r15), %rcx
movq %rcx, 0x28(%rsp)
xorl %ebp, %ebp
movsd 0x4403(%rip), %xmm5     # 0x6018
pushq $0x1
popq %r13
testl %eax, %eax
js 0x1d91
cmpl 0x17d4(%r15), %eax
jge 0x1d91
movl %eax, %r12d
shlq $0x7, %r12
addq 0x28(%rsp), %r12
xorpd %xmm0, %xmm0
xorl %eax, %eax
cmpq $0x4, %rax
je 0x1c7f
movsd (%r14,%rax,8), %xmm1
movapd %xmm1, %xmm2
movhpd 0x10(%r12,%rax,8), %xmm2 # xmm2 = xmm2[0],mem[0]
movsd 0x30(%r12,%rax,8), %xmm3
unpcklpd %xmm1, %xmm3            # xmm3 = xmm3[0],xmm1[0]
subpd %xmm3, %xmm2
maxpd %xmm4, %xmm2
movapd %xmm2, %xmm1
unpckhpd %xmm2, %xmm1            # xmm1 = xmm1[1],xmm2[1]
addsd %xmm2, %xmm1
addsd %xmm1, %xmm0
incq %rax
jmp 0x1c40
movsd 0x17f8(%r15), %xmm3
addsd %xmm0, %xmm3
xorpd %xmm1, %xmm1
xorl %eax, %eax
cmpq $0x2, %rax
je 0x1cb6
movl 0x68(%r12,%rax,4), %ecx
testl %ecx, %ecx
cmovgl %r13d, %ecx
cvtsi2sd %ecx, %xmm2
movsd %xmm2, 0x30(%rsp,%rax,8)
addsd %xmm2, %xmm1
incq %rax
jmp 0x1c92
xorpd 0x4392(%rip), %xmm0     # 0x6050
movsd 0x4352(%rip), %xmm2     # 0x6018
divsd %xmm1, %xmm2
divsd %xmm3, %xmm0
xorl %eax, %eax
cmpq $0x2, %rax
je 0x1d0e
movsd 0x30(%rsp,%rax,8), %xmm3
movapd %xmm0, %xmm4
mulsd %xmm3, %xmm4
addsd %xmm3, %xmm4
movsd (%rbx,%rax,8), %xmm3
mulsd %xmm1, %xmm3
addsd %xmm4, %xmm3
mulsd %xmm2, %xmm3
mulsd %xmm5, %xmm3
addsd 0x10(%rsp,%rax,8), %xmm3
movsd %xmm3, 0x10(%rsp,%rax,8)
incq %rax
jmp 0x1cd0
movsd %xmm5, 0x8(%rsp)
movq %r15, %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x1e42
incl %ebp
cmpl 0x4(%rsp), %ebp
jae 0x1d62
movslq (%r12), %rax
cmpq $-0x1, %rax
je 0x1d62
movsd 0x8(%r12), %xmm0
xorl %ecx, %ecx
ucomisd (%r14,%rax,8), %xmm0
movsd 0x8(%rsp), %xmm5
mulsd 0x42cf(%rip), %xmm5     # 0x6020
setb %cl
movl 0x50(%r12,%rcx,4), %eax
xorpd %xmm4, %xmm4
jmp 0x1c19
xorpd %xmm0, %xmm0
movsd 0x8(%rsp), %xmm1
mulsd %xmm0, %xmm1
xorl %eax, %eax
cmpq $0x2, %rax
je 0x1d91
movsd (%rbx,%rax,8), %xmm0
mulsd %xmm1, %xmm0
addsd 0x10(%rsp,%rax,8), %xmm0
movsd %xmm0, (%rbx,%rax,8)
incq %rax
jmp 0x1d72
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq