// File: /workspace/github_c_makefile_star2_O2/kernfel[P]fNEAT/neat.c
// Function: get_population_fertility
int get_population_fertility( Population *pop, struct NEAT_Params *params, int *num_offspring ) {
	int i, j;
	double species_scores[pop->num_species];
	for ( i=0; i<pop->num_species; i++ ) {
		species_scores[i] = 0.0;
	}

	// Add up all scores within a species
	for ( i=0; i<pop->num_members; i++ ) {
		for ( j=0; j<pop->num_species; j++ ) {
			if ( pop->species[j].id == pop->members[i].species_id ) {
				species_scores[j] += pop->members[i].score;
				#if defined VERBOSE && VERBOSE > 2
					printf( "Member #%5x in species #%3x, score: %2.2f\n", pop->members[i].id, pop->species[j].id, pop->members[i].score );
				#endif
				break;
			}
		}
	}

	double sum_average_scores = 0.0;
	int species_scoresort[pop->num_species];
	for ( i=0; i<pop->num_species; i++ ) {

		// Determine average score
		double mean_score = species_scores[i] / pop->species[i].size;

		// Increase stagnation counter, where appropriate
		if ( fabs( mean_score - pop->species[i].mean_score ) > params->stagnation_score_threshold )
			pop->species[i].stagnating_for = 0;
		else
			pop->species[i].stagnating_for++;

		pop->species[i].mean_score = mean_score;
		sum_average_scores += mean_score;

		// Sort species by average score, descending
		for ( j=0; j<i; j++ ) {
			if ( pop->species[i].mean_score > pop->species[species_scoresort[j]].mean_score ) {
				memmove( species_scoresort+j+1, species_scoresort+j, (i-j)*sizeof *species_scoresort );
				break;
			}
		}
		species_scoresort[j] = i;
	}

	// Assign offspring in proportion to a species' average score
	int unassigned_offspring = params->population_size, living_species=0;
	for ( i=0; i<pop->num_species; i++ ) {
		// Penalise stagnation
		if ( pop->species[i].stagnating_for < params->stagnation_age_threshold )
			num_offspring[i] = (int)(params->population_size * pop->species[i].mean_score/sum_average_scores);
		else
			num_offspring[i] = (int)(params->population_size * (1-params->stagnation_penalty) * pop->species[i].mean_score/sum_average_scores);
		// Kill insular species
		if ( num_offspring[i] < params->extinction_threshold )
			num_offspring[i] = 0;
		
		if ( num_offspring[i] ) {
			living_species++;
			unassigned_offspring -= num_offspring[i];
		}
	}

	if ( ! living_species )
		return E_NO_OFFSPRING;

	// Distribute leftovers
	int shared=unassigned_offspring/living_species, stolen=unassigned_offspring%living_species;
	if ( shared || stolen ) {
		for ( i=0; i<pop->num_species; i++ ) {
			if ( num_offspring[i] ) {
				num_offspring[i] += shared;
				if ( stolen ) {
					num_offspring[i]++;
					stolen--;
				}
			}
		}
	}
	
	#ifdef VERBOSE
		double sd[pop->num_species], dev;
		for ( j=0; j<pop->num_species; j++ ) {
			sd[j] = 0;
			for ( i=0; i<pop->num_members; i++ ) {
				if ( pop->species[j].id == pop->members[i].species_id ) {
					dev = pop->species[j].mean_score - pop->members[i].score;
					sd[j] += dev*dev;
				}
			}
			sd[j] = sqrt(sd[j]/pop->species[j].size);
		}
		
		for ( i=0; i<pop->num_species; i++ ) {
			printf( "Species #%3x (idx %2d) - %3d members, %3d offspring - total score: %8.2f | avg score: %8.2f | sd: %4.2f\n",
				pop->species[i].id,
				i,
				pop->species[i].size,
				num_offspring[i],
				species_scores[i],
				pop->species[i].mean_score,
				sd[i]
			);
		}
	#endif
	
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rsi, %r15
movq %rdi, %r14
movl 0x18(%rdi), %r9d
movq %rsp, %rcx
leaq 0xf(,%r9,8), %rax
andq $-0x10, %rax
subq %rax, %rcx
movq %rcx, -0x30(%rbp)
movq %rcx, %rsp
xorl %eax, %eax
testl %r9d, %r9d
movl $0x0, %r12d
cmovgl %r9d, %r12d
movq -0x30(%rbp), %rcx
cmpq %rax, %r12
je 0x3db5
andq $0x0, (%rcx,%rax,8)
incq %rax
jmp 0x3da6
movl 0x8(%r14), %eax
xorl %ecx, %ecx
testl %eax, %eax
cmovlel %ecx, %eax
movq -0x30(%rbp), %rsi
leaq -0x8(%rsi), %rbx
imulq $0x18, %r12, %rsi
movq %r9, -0x38(%rbp)
cmpq %rax, %rcx
je 0x3e18
imulq $0x38, %rcx, %r8
xorl %r9d, %r9d
movq %rbx, %rdi
cmpq %r9, %rsi
je 0x3e0f
movq (%r14), %r10
movq 0x10(%r14), %r11
movl (%r11,%r9), %r11d
addq $0x8, %rdi
addq $0x18, %r9
cmpl 0x30(%r10,%r8), %r11d
jne 0x3ddf
addq %r8, %r10
movsd 0x28(%r10), %xmm0
addsd (%rdi), %xmm0
movsd %xmm0, (%rdi)
incq %rcx
movq -0x38(%rbp), %r9
jmp 0x3dd0
movq %r12, -0x58(%rbp)
movq %rdx, -0x40(%rbp)
movq %rsp, %rbx
leaq 0xf(,%r9,4), %rax
andq $-0x10, %rax
subq %rax, %rbx
movq %rbx, %rsp
xorpd %xmm3, %xmm3
xorl %r13d, %r13d
movapd 0x23fc(%rip), %xmm2     # 0x6240
xorl %r12d, %r12d
movq %r15, -0x50(%rbp)
cmpq -0x58(%rbp), %r12
je 0x3f09
movq -0x30(%rbp), %rax
movsd (%rax,%r12,8), %xmm0
movq 0x10(%r14), %rax
imulq $0x18, %r12, %rcx
leaq (%rax,%rcx), %rdx
cvtsi2sdl 0x4(%rax,%rcx), %xmm1
divsd %xmm1, %xmm0
movapd %xmm0, %xmm1
subsd 0x10(%rax,%rcx), %xmm1
andpd %xmm2, %xmm1
xorl %esi, %esi
ucomisd 0xa0(%r15), %xmm1
ja 0x3e95
movl 0x8(%rdx), %esi
incl %esi
movl %esi, 0x8(%rdx)
movsd %xmm0, 0x10(%rax,%rcx)
addsd %xmm0, %xmm3
movq %r13, %rdx
xorl %r15d, %r15d
testq %rdx, %rdx
je 0x3ec6
movslq (%rbx,%r15,4), %rcx
imulq $0x18, %rcx, %rcx
ucomisd 0x10(%rax,%rcx), %xmm0
ja 0x3ecb
incq %r15
addq $-0x4, %rdx
jmp 0x3ea8
movq %r12, %r15
jmp 0x3ef2
leaq (%rbx,%r15,4), %rsi
leaq (%rbx,%r15,4), %rdi
addq $0x4, %rdi
movsd %xmm3, -0x48(%rbp)
callq 0x1110
movapd 0x2357(%rip), %xmm2     # 0x6240
movsd -0x48(%rbp), %xmm3
movq -0x38(%rbp), %r9
movl %r15d, %eax
movl %r12d, (%rbx,%rax,4)
incq %r12
addq $0x4, %r13
movq -0x50(%rbp), %r15
jmp 0x3e4b
movl 0x50(%r15), %eax
xorl %ecx, %ecx
pushq $0x4
popq %rdx
movsd 0x21f6(%rip), %xmm0     # 0x6110
xorl %edi, %edi
xorl %esi, %esi
movq -0x40(%rbp), %r12
movslq %r9d, %r8
cmpq %r8, %rdi
jge 0x3f89
movq 0x10(%r14), %r8
movl -0x8(%r8,%rdx,4), %r9d
cvtsi2sdl 0x50(%r15), %xmm1
cmpl 0x98(%r15), %r9d
jl 0x3f53
movapd %xmm0, %xmm2
subsd 0xa8(%r15), %xmm2
mulsd %xmm2, %xmm1
mulsd (%r8,%rdx,4), %xmm1
divsd %xmm3, %xmm1
cvttsd2si %xmm1, %r8d
movl %r8d, (%r12,%rdi,4)
cmpl %r8d, 0x54(%r15)
cmovgl %ecx, %r8d
subl %r8d, %eax
cmpl $0x1, %r8d
sbbl $-0x1, %esi
movl %r8d, (%r12,%rdi,4)
incq %rdi
movl 0x18(%r14), %r9d
addq $0x6, %rdx
jmp 0x3f22
testl %esi, %esi
je 0x40ce
cltd
idivl %esi
movl %edx, %ecx
orl %eax, %ecx
je 0x3fcb
xorl %ecx, %ecx
movslq %r9d, %rsi
cmpq %rsi, %rcx
jge 0x3fcb
movl (%r12,%rcx,4), %esi
testl %esi, %esi
je 0x3fc2
addl %eax, %esi
movl %esi, (%r12,%rcx,4)
testl %edx, %edx
je 0x3fc0
incl %esi
movl %esi, (%r12,%rcx,4)
decl %edx
jmp 0x3fc2
xorl %edx, %edx
incq %rcx
movl 0x18(%r14), %r9d
jmp 0x3f9c
movl %r9d, %eax
movq %rsp, %r15
leaq 0xf(,%rax,8), %rax
andq $-0x10, %rax
subq %rax, %r15
movq %r15, %rsp
xorl %ebx, %ebx
xorpd %xmm2, %xmm2
xorl %r13d, %r13d
movslq %r9d, %rax
cmpq %rax, %r13
jge 0x407a
movl 0x8(%r14), %esi
testl %esi, %esi
cmovlel %ebx, %esi
movq 0x10(%r14), %rax
imulq $0x18, %r13, %rcx
leaq (%rax,%rcx), %rdx
imulq $0x38, %rsi, %rsi
xorpd %xmm0, %xmm0
xorl %edi, %edi
cmpq %rdi, %rsi
je 0x4049
movl (%rdx), %r9d
movq (%r14), %r8
cmpl 0x30(%r8,%rdi), %r9d
jne 0x4043
movsd 0x10(%rdx), %xmm1
subsd 0x28(%r8,%rdi), %xmm1
mulsd %xmm1, %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, (%r15,%r13,8)
addq $0x38, %rdi
jmp 0x4017
cvtsi2sdl 0x4(%rax,%rcx), %xmm1
divsd %xmm1, %xmm0
ucomisd %xmm2, %xmm0
jb 0x405f
sqrtsd %xmm0, %xmm0
jmp 0x4068
callq 0x1180
xorpd %xmm2, %xmm2
movsd %xmm0, (%r15,%r13,8)
incq %r13
movl 0x18(%r14), %r9d
jmp 0x3fec
xorl %ebx, %ebx
xorl %r13d, %r13d
movslq %r9d, %rax
cmpq %rax, %r13
jge 0x40ca
movq 0x10(%r14), %rax
movl (%rax,%rbx), %esi
movl 0x4(%rax,%rbx), %ecx
movl (%r12,%r13,4), %r8d
movq -0x30(%rbp), %rdx
movsd (%rdx,%r13,8), %xmm0
movsd 0x10(%rax,%rbx), %xmm1
movsd (%r15,%r13,8), %xmm2
leaq 0x221d(%rip), %rdi      # 0x62d0
movl %r13d, %edx
movb $0x3, %al
callq 0x1050
incq %r13
movl 0x18(%r14), %r9d
addq $0x18, %rbx
jmp 0x407f
xorl %eax, %eax
jmp 0x40d1
pushq $-0xa
popq %rax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq