// File: /workspace/github_c_makefile_star2_O3/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 $0x48, %rsp
movq %rdx, %r14
movq %rsi, %r12
movq %rdi, %r15
movl 0x18(%rdi), %r10d
movq %rsp, %rdi
leaq 0xf(,%r10,8), %rax
andq $-0x10, %rax
subq %rax, %rdi
movq %rdi, %rsp
testl %r10d, %r10d
movq %rdi, -0x30(%rbp)
movq %r10, -0x40(%rbp)
jle 0x4325
leaq (,%r10,8), %rdx
xorl %esi, %esi
callq 0x1060
movq -0x40(%rbp), %r10
movq -0x30(%rbp), %rdi
movslq 0x8(%r15), %rax
testq %rax, %rax
jle 0x4378
xorl %ecx, %ecx
testl %r10d, %r10d
jle 0x4370
movq (%r15), %r9
movq 0x10(%r15), %rdx
imulq $0x38, %rcx, %r8
leaq (%r9,%r8), %rsi
movl 0x30(%r9,%r8), %r8d
xorl %r9d, %r9d
cmpl %r8d, (%rdx)
je 0x435f
incq %r9
addq $0x18, %rdx
cmpq %r9, %r10
jne 0x434c
jmp 0x4370
movsd 0x28(%rsi), %xmm0
addsd (%rdi,%r9,8), %xmm0
movsd %xmm0, (%rdi,%r9,8)
incq %rcx
cmpq %rax, %rcx
jne 0x4330
movq %rsp, %rbx
leaq 0xf(,%r10,4), %rax
andq $-0x10, %rax
subq %rax, %rbx
movq %rbx, %rsp
movl $0xfffffff6, %edx       # imm = 0xFFFFFFF6
testl %r10d, %r10d
jle 0x467b
movq %r14, -0x58(%rbp)
movq %r15, -0x50(%rbp)
movq 0x10(%r15), %r15
movq %r12, -0x48(%rbp)
movsd 0xa0(%r12), %xmm1
xorpd %xmm3, %xmm3
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
xorl %r12d, %r12d
movapd 0x2ec7(%rip), %xmm2     # 0x7290
xorl %r14d, %r14d
movsd %xmm1, -0x60(%rbp)
movsd (%rdi,%r14,8), %xmm4
leaq (%r14,%r14,2), %rax
leaq (%r15,%rax,8), %rcx
xorps %xmm0, %xmm0
cvtsi2sdl 0x4(%rcx), %xmm0
divsd %xmm0, %xmm4
movapd %xmm4, %xmm0
subsd 0x10(%rcx), %xmm0
andpd %xmm2, %xmm0
ucomisd %xmm1, %xmm0
movl $0x0, %edx
ja 0x4408
movl 0x8(%rcx), %edx
incl %edx
incl %esi
movl %edx, 0x8(%rcx)
movsd %xmm4, 0x10(%r15,%rax,8)
testq %r14, %r14
je 0x443e
movq %r12, %rdx
xorl %r13d, %r13d
movslq (%rbx,%r13,4), %rax
leaq (%rax,%rax,2), %rax
ucomisd 0x10(%r15,%rax,8), %xmm4
ja 0x4443
incq %r13
addq $-0x4, %rdx
jne 0x441f
movl %esi, %r13d
jmp 0x4483
xorl %r13d, %r13d
jmp 0x4483
movl %esi, -0x34(%rbp)
leaq (%rbx,%r13,4), %rsi
leaq (%rbx,%r13,4), %rdi
addq $0x4, %rdi
movsd %xmm3, -0x70(%rbp)
movsd %xmm4, -0x68(%rbp)
callq 0x1110
movsd -0x68(%rbp), %xmm4
movapd 0x2e22(%rip), %xmm2     # 0x7290
movl -0x34(%rbp), %esi
movsd -0x60(%rbp), %xmm1
movsd -0x70(%rbp), %xmm3
movq -0x40(%rbp), %r10
movq -0x30(%rbp), %rdi
addsd %xmm4, %xmm3
movl %r13d, %eax
movl %r14d, (%rbx,%rax,4)
incq %r14
addq $0x4, %r12
cmpq %r10, %r14
jne 0x43d1
testl %r10d, %r10d
jle 0x4676
movq -0x48(%rbp), %r10
movl 0x50(%r10), %eax
movq -0x50(%rbp), %r15
movq 0x10(%r15), %rdx
addq $0x10, %rdx
xorl %r9d, %r9d
movsd 0x2c6a(%rip), %xmm0     # 0x7130
xorl %r8d, %r8d
xorl %ecx, %ecx
movq -0x58(%rbp), %r14
movl -0x8(%rdx), %esi
xorps %xmm1, %xmm1
cvtsi2sdl 0x50(%r10), %xmm1
cmpl 0x98(%r10), %esi
jl 0x44f5
movapd %xmm0, %xmm2
subsd 0xa8(%r10), %xmm2
mulsd %xmm2, %xmm1
mulsd (%rdx), %xmm1
divsd %xmm3, %xmm1
cvttsd2si %xmm1, %esi
movl %esi, (%r14,%r8,4)
cmpl %esi, 0x54(%r10)
cmovgl %r9d, %esi
movl %esi, (%r14,%r8,4)
subl %esi, %eax
cmpl $0x1, %esi
sbbl $-0x1, %ecx
incq %r8
movslq 0x18(%r15), %rsi
addq $0x18, %rdx
cmpq %rsi, %r8
jl 0x44cf
testl %ecx, %ecx
movl $0xfffffff6, %edx       # imm = 0xFFFFFFF6
je 0x467b
cltd
idivl %ecx
movl %edx, %ecx
orl %eax, %ecx
je 0x4573
testl %esi, %esi
jle 0x4672
xorl %ecx, %ecx
movl (%r14,%rcx,4), %esi
testl %esi, %esi
je 0x4567
addl %eax, %esi
movl %esi, (%r14,%rcx,4)
testl %edx, %edx
je 0x4565
incl %esi
movl %esi, (%r14,%rcx,4)
decl %edx
jmp 0x4567
xorl %edx, %edx
incq %rcx
movslq 0x18(%r15), %rsi
cmpq %rsi, %rcx
jl 0x4549
movl %esi, %eax
movq %rsp, %r12
leaq 0xf(,%rax,8), %rax
andq $-0x10, %rax
subq %rax, %r12
movq %r12, %rsp
testl %esi, %esi
jle 0x4672
xorl %ebx, %ebx
xorpd %xmm2, %xmm2
movslq 0x8(%r15), %r8
movq 0x10(%r15), %rax
leaq (%rbx,%rbx,2), %rcx
xorpd %xmm0, %xmm0
testq %r8, %r8
jle 0x45e7
leaq (%rax,%rcx,8), %rdx
movl (%rdx), %esi
movq (%r15), %r10
imulq $0x38, %r8, %r8
xorl %r9d, %r9d
cmpl 0x30(%r10,%r9), %esi
jne 0x45de
movsd 0x10(%rdx), %xmm1
subsd 0x28(%r10,%r9), %xmm1
mulsd %xmm1, %xmm1
addsd %xmm1, %xmm0
movsd %xmm0, (%r12,%rbx,8)
addq $0x38, %r9
cmpq %r9, %r8
jne 0x45bd
xorps %xmm1, %xmm1
cvtsi2sdl 0x4(%rax,%rcx,8), %xmm1
divsd %xmm1, %xmm0
ucomisd %xmm2, %xmm0
jb 0x4600
sqrtsd %xmm0, %xmm0
jmp 0x460d
callq 0x1180
xorpd %xmm2, %xmm2
movq -0x30(%rbp), %rdi
movsd %xmm0, (%r12,%rbx,8)
incq %rbx
movslq 0x18(%r15), %rax
cmpq %rax, %rbx
jl 0x4598
testl %eax, %eax
jle 0x4672
xorl %ebx, %ebx
xorl %r13d, %r13d
movq 0x10(%r15), %rax
movl (%rax,%rbx), %esi
movl 0x4(%rax,%rbx), %ecx
movl (%r14,%r13,4), %r8d
movsd (%rdi,%r13,8), %xmm0
movsd 0x10(%rax,%rbx), %xmm1
movsd (%r12,%r13,8), %xmm2
leaq 0x2cec(%rip), %rdi      # 0x7340
movl %r13d, %edx
movb $0x3, %al
callq 0x1050
movq -0x30(%rbp), %rdi
incq %r13
movslq 0x18(%r15), %rax
addq $0x18, %rbx
cmpq %rax, %r13
jl 0x462c
xorl %edx, %edx
jmp 0x467b
movl $0xfffffff6, %edx       # imm = 0xFFFFFFF6
movl %edx, %eax
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq