// File: /workspace/github_cpp_makefile_star2_O1/richardposner[P]BioNetFit2/src/code/Swarm.cpp
// Function: Swarm::mutateParticleSA(unsigned int, float)
vector<double> Swarm::mutateParticleSA(unsigned int particle, float mutateFactor) {

	if (options.verbosity >= 3) {
		cout << "Mutating particle " << particle << endl;
	}

	vector<double> mutatedParams;

	// f between 0.1 and 0.9
	//float f = 0.1 + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(0.9-0.1)));
	float f;
	if (mutateFactor) {
		f = mutateFactor;
	}
	else {
		f = 0.9;
	}

	boost::random::uniform_int_distribution<int> unif(1, options.swarmSize);

	if (options.mutateType == 1) {
		int bestParticle = 0;
		for (auto fitVal = particleBestFitsByFit_.begin(); fitVal != particleBestFitsByFit_.end(); ++fitVal) {
			if (fitVal->first > 0 ) {
				bestParticle = fitVal->second;
				//cout << "setting particle " << fitVal->second << " as best with fit of " << fitVal -> first << endl;
				break;
			}
		}
		vector<double> bestParamSet = normalizeParams(particleCurrParamSets_.at(bestParticle));
		unsigned int pi = 0;
		for (auto param = this->getFreeParams_().begin(); param != this->getFreeParams_().end(); ++param) {//for (auto param = options.model->getFreeParams_().begin(); param != options.model->getFreeParams_().end(); ++param) {
			int p1 = 0;
			int p2 = 0;

			while (p1 == p2) {
				p1 = unif(generalRand);
				p2 = unif(generalRand);
			}

			//cout << "p1: " << p1 << " p2: " << p2 << " pi: " << pi << endl;
			double p1Param = normalizeParam(particleCurrParamSets_.at(p1)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p2Param = normalizeParam(particleCurrParamSets_.at(p2)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			mutatedParams.push_back(bestParamSet[pi] + f * (p1Param - p2Param));
			++pi;
		}
	}
	else if (options.mutateType == 2) {
		unsigned int pi = 0;
		int bestParticle = 0;
		for (auto fitVal = particleBestFitsByFit_.begin(); fitVal != particleBestFitsByFit_.end(); ++fitVal) {
			if (fitVal->first > 0) {
				bestParticle = fitVal->second;
			}
		}
		vector<double> bestParamSet = normalizeParams(particleCurrParamSets_.at(bestParticle));
		for (auto param = this->getFreeParams_().begin(); param != this->getFreeParams_().end(); ++param) { //for (auto param = options.model->getFreeParams_().begin(); param != options.model->getFreeParams_().end(); ++param) {
			int p1 = 0;
			int p2 = 0;
			int p3 = 0;
			int p4 = 0;
			while (p1 == p2 || p1 == p3 || p1 == p4 || p2 == p3 || p2 == p4 || p3 == p4) {
				p1 = unif(generalRand);
				p2 = unif(generalRand);
				p3 = unif(generalRand);
				p4 = unif(generalRand);
			}

			double p1Param = normalizeParam(particleCurrParamSets_.at(p1)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p2Param = normalizeParam(particleCurrParamSets_.at(p2)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p3Param = normalizeParam(particleCurrParamSets_.at(p3)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p4Param = normalizeParam(particleCurrParamSets_.at(p4)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());

			mutatedParams.push_back(bestParamSet[pi] + f * (p1Param - p2Param) + f * (p3Param - p4Param));
			++pi;
		}
	}
	else if (options.mutateType == 3) {
		unsigned int pi = 0;
		int bestParticle = 0;
		for (auto fitVal = particleBestFitsByFit_.begin(); fitVal != particleBestFitsByFit_.end(); ++fitVal) {
			if (fitVal->first > 0) {
				bestParticle = fitVal->second;
			}
		}
		vector<double> bestParamSet = normalizeParams(particleCurrParamSets_.at(bestParticle));
		for (auto param = this->getFreeParams_().begin(); param != this->getFreeParams_().end(); ++param) { //for (auto param = options.model->getFreeParams_().begin(); param != options.model->getFreeParams_().end(); ++param) {
			int p1 = 0;
			int p2 = 0;
			int p3 = 0;
			while (p1 == p2 || p1 == p3 || p2 == p3) {
				p1 = unif(generalRand);
				p2 = unif(generalRand);
				p3 = unif(generalRand);
			}

			double p1Param = normalizeParam(particleCurrParamSets_.at(p1)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p2Param = normalizeParam(particleCurrParamSets_.at(p2)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p3Param = normalizeParam(particleCurrParamSets_.at(p3)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());

			mutatedParams.push_back(p1Param + f * (p2Param - p3Param));
			++pi;
		}
	}
	else if (options.mutateType == 4) {
		unsigned int pi = 0;
		int bestParticle = 0;
		for (auto fitVal = particleBestFitsByFit_.begin(); fitVal != particleBestFitsByFit_.end(); ++fitVal) {
			if (fitVal->first > 0) {
				bestParticle = fitVal->second;
			}
		}
		vector<double> bestParamSet = normalizeParams(particleCurrParamSets_.at(bestParticle));
		for (auto param = this->getFreeParams_().begin(); param != this->getFreeParams_().end(); ++param) {  //for (auto param = options.model->getFreeParams_().begin(); param != options.model->getFreeParams_().end(); ++param) {
			int p1 = 0;
			int p2 = 0;
			int p3 = 0;
			int p4 = 0;
			int p5 = 0;
			// This (and above instances) should be optimized
			while (p1 == p2 || p1 == p3 || p1 == p4 || p2 == p3 || p2 == p4 || p3 == p4 || p1 == p5 || p2 == p5 || p3 == p5 || p4 == p5) {
				p1 = unif(generalRand);
				p2 = unif(generalRand);
				p3 = unif(generalRand);
				p4 = unif(generalRand);
				p5 = unif(generalRand);
			}

			double p1Param = normalizeParam(particleCurrParamSets_.at(p1)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p2Param = normalizeParam(particleCurrParamSets_.at(p2)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p3Param = normalizeParam(particleCurrParamSets_.at(p3)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p4Param = normalizeParam(particleCurrParamSets_.at(p4)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());
			double p5Param = normalizeParam(particleCurrParamSets_.at(p5)[pi], param->second->getGenMin(), param->second->getGenMax(), param->second->getIsLog());

			mutatedParams.push_back(p1Param + f * (p2Param - p3Param) + f * (p4Param - p5Param));
			++pi;
		}
	}

	return mutatedParams;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x88, %rsp
movq %rsi, %r14
movq %rdi, %rbx
cmpl $0x3, 0x1614(%rsi)
jb 0xa2a11
movl %edx, %ebp
movq 0xd35c7(%rip), %r15     # 0x175f90
leaq 0x5edd6(%rip), %rsi     # 0x1017a6
movl $0x12, %edx
movq %r15, %rdi
callq 0x22ab0
movl %ebp, %esi
movq %r15, %rdi
callq 0x22650
movq %rax, %r15
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x22940
movsbl %al, %esi
movq %r15, %rdi
callq 0x22050
movq %rax, %rdi
callq 0x22660
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
movq $0x0, 0x10(%rbx)
cmpl $0x0, 0x1620(%r14)
jle 0xa2a90
movl 0x1700(%r14), %eax
decl %eax
cmpl $0x3, %eax
jbe 0xa2a4a
movq %rbx, %rax
addq $0x88, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0x5b5d7(%rip), %rcx     # 0xfe028
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0xa2bdb
movsd 0x20(%rax), %xmm0
ucomisd 0x540b8(%rip), %xmm0    # 0xf6b38
ja 0xa2bd8
movq %rax, %rdi
callq 0x22670
jmp 0xa2a6a
leaq 0x744d1(%rip), %rdi     # 0x116f68
leaq 0x744dd(%rip), %rsi     # 0x116f7b
leaq 0x7450d(%rip), %rcx     # 0x116fb2
movl $0x151, %edx            # imm = 0x151
callq 0x22610
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0xa2ae5
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x54065(%rip), %xmm0    # 0xf6b38
jbe 0xa2ad8
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r15, %rax
jne 0xa2ac6
leaq 0x1400(%r14), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa837c
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x66228
leaq 0x10(%rsp), %rdi
movq %r14, %rsi
callq 0xa2910
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0xa2b48
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x54002(%rip), %xmm0    # 0xf6b38
jbe 0xa2b3b
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r15, %rax
jne 0xa2b29
leaq 0x1400(%r14), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa837c
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x66228
leaq 0x10(%rsp), %rdi
movq %r14, %rsi
callq 0xa2910
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0xa2bab
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x53f9f(%rip), %xmm0    # 0xf6b38
jbe 0xa2b9e
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r15, %rax
jne 0xa2b8c
leaq 0x1400(%r14), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa837c
leaq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x66228
leaq 0x10(%rsp), %rdi
movq %r14, %rsi
callq 0xa2910
movl 0x28(%rax), %ebp
leaq 0x1400(%r14), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa837c
leaq 0x70(%rsp), %rdi
movq %rax, %rsi
callq 0x66228
leaq 0x10(%rsp), %rdi
movq %r14, %rsi
callq 0xa2910
movq %rax, %r14
movq 0x70(%rsp), %rdi
testq %rdi, %rdi
je 0xa2c6c
movq 0x80(%rsp), %rsi
jmp 0xa2c59
movq %rax, %r14
movq 0x58(%rsp), %rdi
testq %rdi, %rdi
je 0xa2c6c
movq 0x68(%rsp), %rsi
jmp 0xa2c59
movq %rax, %r14
movq 0x28(%rsp), %rdi
testq %rdi, %rdi
je 0xa2c6c
movq 0x38(%rsp), %rsi
jmp 0xa2c59
movq %rax, %r14
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0xa2c6c
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x229c0
jmp 0xa2c6c
jmp 0xa2c69
jmp 0xa2c69
jmp 0xa2c69
movq %rax, %r14
movq (%rbx), %rdi
testq %rdi, %rdi
je 0xa2c80
movq 0x10(%rbx), %rsi
subq %rdi, %rsi
callq 0x229c0
movq %r14, %rdi
callq 0x23240