// File: 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
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq %rcx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0xd8(%rbp)
callq 0x2a30
movslq -0x14(%rbp), %rcx
imulq $0x38, %rcx, %rcx
addq %rcx, %rax
movl 0x8(%rax), %eax
movl %eax, -0x28(%rbp)
movl $0x0, -0x2c(%rbp)
movl $0x0, -0x30(%rbp)
cmpl $0x2, -0x30(%rbp)
jge 0x235a
movq -0xd8(%rbp), %rax
movsd 0x17f0(%rax), %xmm0
movq -0x20(%rbp), %rax
movslq -0x30(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x232d
cmpl $-0x1, -0x28(%rbp)
jne 0x2365
jmp 0x2860
xorps %xmm0, %xmm0
movsd %xmm0, -0x38(%rbp)
movsd 0x8ca3(%rip), %xmm0     # 0xb018
movsd %xmm0, -0x40(%rbp)
movsd 0x8c96(%rip), %xmm0     # 0xb018
movsd %xmm0, -0x50(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x58(%rbp)
leaq -0x70(%rbp), %rdi
xorl %esi, %esi
movl $0x10, %edx
callq 0x1030
xorl %eax, %eax
cmpl $0x0, -0x28(%rbp)
movb %al, -0xd9(%rbp)
jl 0x23c6
movq -0xd8(%rbp), %rcx
movl -0x28(%rbp), %eax
cmpl 0x17d4(%rcx), %eax
setl %al
movb %al, -0xd9(%rbp)
movb -0xd9(%rbp), %al
testb $0x1, %al
jne 0x23d5
jmp 0x2860
movq -0xd8(%rbp), %rdi
callq 0x2a60
movslq -0x28(%rbp), %rcx
shlq $0x7, %rcx
addq %rcx, %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
movsd 0x60(%rax), %xmm0
subsd -0x58(%rbp), %xmm0
movsd %xmm0, -0x80(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x88(%rbp)
movl $0x0, -0x8c(%rbp)
cmpl $0x4, -0x8c(%rbp)
jge 0x24b2
movq -0x10(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x78(%rbp), %rax
movslq -0x8c(%rbp), %rcx
subsd 0x30(%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
callq 0x2a80
movsd %xmm0, -0xe8(%rbp)
movq -0x78(%rbp), %rax
movslq -0x8c(%rbp), %rcx
movsd 0x10(%rax,%rcx,8), %xmm0
movq -0x10(%rbp), %rax
movslq -0x8c(%rbp), %rcx
subsd (%rax,%rcx,8), %xmm0
xorps %xmm1, %xmm1
callq 0x2a80
movaps %xmm0, %xmm1
movsd -0xe8(%rbp), %xmm0
addsd %xmm1, %xmm0
addsd -0x88(%rbp), %xmm0
movsd %xmm0, -0x88(%rbp)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x2418
movsd -0x80(%rbp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd -0x88(%rbp), %xmm0
callq 0x2ac0
movaps %xmm0, %xmm1
movsd 0x8b32(%rip), %xmm0     # 0xb018
subsd %xmm1, %xmm0
movsd %xmm0, -0x48(%rbp)
movsd -0x48(%rbp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x273b
movq -0xd8(%rbp), %rax
movsd -0x88(%rbp), %xmm0
movsd -0x88(%rbp), %xmm1
addsd 0x17f8(%rax), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0xf8(%rbp)
movsd -0x88(%rbp), %xmm0
addsd 0x17f8(%rax), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd -0x80(%rbp), %xmm0
callq 0x2ad0
movaps %xmm0, %xmm1
movsd -0xf8(%rbp), %xmm0
movq %xmm1, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -0xf0(%rbp)
movsd -0x88(%rbp), %xmm0
mulsd -0x80(%rbp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
callq 0x2ad0
movaps %xmm0, %xmm1
movsd -0xf0(%rbp), %xmm0
movq %xmm1, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x98(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0xb8(%rbp)
movl $0x0, -0xbc(%rbp)
cmpl $0x2, -0xbc(%rbp)
jge 0x265e
movq -0x78(%rbp), %rax
movslq -0xbc(%rbp), %rcx
movl 0x68(%rax,%rcx,4), %edi
movl $0x1, %esi
callq 0x2a00
cvtsi2sd %eax, %xmm0
movslq -0xbc(%rbp), %rax
movsd %xmm0, -0xb0(%rbp,%rax,8)
movslq -0xbc(%rbp), %rax
movsd -0xb0(%rbp,%rax,8), %xmm0
addsd -0xb8(%rbp), %xmm0
movsd %xmm0, -0xb8(%rbp)
movl -0xbc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xbc(%rbp)
jmp 0x25f7
movl $0x0, -0xc0(%rbp)
cmpl $0x2, -0xc0(%rbp)
jge 0x2739
movsd 0x899b(%rip), %xmm0     # 0xb018
divsd -0xb8(%rbp), %xmm0
movslq -0xc0(%rbp), %rax
movsd -0xb0(%rbp,%rax,8), %xmm1
movsd -0x98(%rbp), %xmm2
movslq -0xc0(%rbp), %rax
movsd -0xb0(%rbp,%rax,8), %xmm3
movq %xmm2, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm2
mulsd %xmm3, %xmm2
addsd %xmm1, %xmm2
movsd -0xb8(%rbp), %xmm1
movq -0x20(%rbp), %rax
movslq -0xc0(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm3
mulsd %xmm3, %xmm1
addsd %xmm2, %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -0xc8(%rbp)
movsd -0x50(%rbp), %xmm0
mulsd -0x48(%rbp), %xmm0
movsd -0xc8(%rbp), %xmm2
movslq -0xc0(%rbp), %rax
movsd -0x70(%rbp,%rax,8), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x70(%rbp,%rax,8)
movl -0xc0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xc0(%rbp)
jmp 0x2668
jmp 0x273b
movq -0xd8(%rbp), %rdi
movq -0x78(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x2b00
movl -0x2c(%rbp), %ecx
addl $0x1, %ecx
xorl %eax, %eax
cmpl -0x24(%rbp), %ecx
movb %al, -0xf9(%rbp)
jl 0x276f
cmpl $0x0, -0x24(%rbp)
setge %al
movb %al, -0xf9(%rbp)
movb -0xf9(%rbp), %al
andb $0x1, %al
movb %al, -0xc9(%rbp)
testb $0x1, -0xc9(%rbp)
jne 0x2795
movq -0x78(%rbp), %rdi
callq 0x29e0
testb $0x1, %al
jne 0x2795
jmp 0x2806
movl $0x0, -0xd0(%rbp)
cmpl $0x2, -0xd0(%rbp)
jge 0x2804
movslq -0xd0(%rbp), %rax
movsd -0x70(%rbp,%rax,8), %xmm1
movsd -0x50(%rbp), %xmm0
movsd 0x8856(%rip), %xmm2     # 0xb018
subsd -0x48(%rbp), %xmm2
mulsd %xmm2, %xmm0
movq -0x20(%rbp), %rax
movslq -0xd0(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm2
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movq -0x20(%rbp), %rax
movslq -0xd0(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0xd0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xd0(%rbp)
jmp 0x279f
jmp 0x2860
movsd 0x880a(%rip), %xmm0     # 0xb018
subsd -0x48(%rbp), %xmm0
mulsd -0x50(%rbp), %xmm0
movsd %xmm0, -0x50(%rbp)
movq -0x10(%rbp), %rax
movq -0x78(%rbp), %rcx
movslq (%rcx), %rcx
movsd (%rax,%rcx,8), %xmm1
movq -0x78(%rbp), %rax
movsd 0x8(%rax), %xmm0
ucomisd %xmm1, %xmm0
jb 0x2848
movq -0x78(%rbp), %rax
movl 0x50(%rax), %eax
movl %eax, -0x28(%rbp)
jmp 0x2852
movq -0x78(%rbp), %rax
movl 0x54(%rax), %eax
movl %eax, -0x28(%rbp)
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x239f
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
nopl (%rax)