// File: /workspace/github_cpp_makefile_star2_O3/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, %rbx
movq %rdi, %r14
cmpl $0x3, 0x1614(%rsi)
jb 0xa1f43
movl %edx, %ebp
movq 0xd40ad(%rip), %r15     # 0x175fa8
leaq 0x5f88b(%rip), %rsi     # 0x10178d
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, (%r14)
movq $0x0, 0x10(%r14)
cmpl $0x0, 0x1620(%rbx)
jle 0xa1fc1
movl 0x1700(%rbx), %eax
decl %eax
cmpl $0x3, %eax
jbe 0xa1f7b
movq %r14, %rax
addq $0x88, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0x5c116(%rip), %rcx     # 0xfe098
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x1ac8(%rbx), %rax
leaq 0x1ab8(%rbx), %r14
xorl %ebp, %ebp
cmpq %r14, %rax
je 0xa210c
movsd 0x20(%rax), %xmm0
ucomisd 0x54b37(%rip), %xmm0    # 0xf6ae8
ja 0xa2109
movq %rax, %rdi
callq 0x22670
jmp 0xa1f9b
leaq 0x74f87(%rip), %rdi     # 0x116f4f
leaq 0x74f93(%rip), %rsi     # 0x116f62
leaq 0x74fc3(%rip), %rcx     # 0x116f99
movl $0x151, %edx            # imm = 0x151
callq 0x22610
movq 0x1ac8(%rbx), %rax
leaq 0x1ab8(%rbx), %r14
xorl %ebp, %ebp
cmpq %r14, %rax
je 0xa2016
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x54ae4(%rip), %xmm0    # 0xf6ae8
jbe 0xa2009
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r14, %rax
jne 0xa1ff7
leaq 0x1400(%rbx), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa7a46
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x65d5c
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0xa1e5c
movq 0x1ac8(%rbx), %rax
leaq 0x1ab8(%rbx), %r14
xorl %ebp, %ebp
cmpq %r14, %rax
je 0xa2079
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x54a81(%rip), %xmm0    # 0xf6ae8
jbe 0xa206c
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r14, %rax
jne 0xa205a
leaq 0x1400(%rbx), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa7a46
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x65d5c
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0xa1e5c
movq 0x1ac8(%rbx), %rax
leaq 0x1ab8(%rbx), %r14
xorl %ebp, %ebp
cmpq %r14, %rax
je 0xa20dc
xorl %ebp, %ebp
movsd 0x20(%rax), %xmm0
ucomisd 0x54a1e(%rip), %xmm0    # 0xf6ae8
jbe 0xa20cf
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x22670
cmpq %r14, %rax
jne 0xa20bd
leaq 0x1400(%rbx), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa7a46
leaq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x65d5c
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0xa1e5c
movl 0x28(%rax), %ebp
leaq 0x1400(%rbx), %rdi
leaq 0xc(%rsp), %rsi
movl %ebp, (%rsi)
callq 0xa7a46
leaq 0x70(%rsp), %rdi
movq %rax, %rsi
callq 0x65d5c
leaq 0x10(%rsp), %rdi
movq %rbx, %rsi
callq 0xa1e5c
movq %rax, %rbx
movq 0x70(%rsp), %rdi
testq %rdi, %rdi
je 0xa219d
movq 0x80(%rsp), %rsi
jmp 0xa218a
movq %rax, %rbx
movq 0x58(%rsp), %rdi
testq %rdi, %rdi
je 0xa219d
movq 0x68(%rsp), %rsi
jmp 0xa218a
movq %rax, %rbx
movq 0x28(%rsp), %rdi
testq %rdi, %rdi
je 0xa219d
movq 0x38(%rsp), %rsi
jmp 0xa218a
movq %rax, %rbx
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0xa219d
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x229c0
jmp 0xa219d
jmp 0xa219a
jmp 0xa219a
jmp 0xa219a
movq %rax, %rbx
movq %rbx, %rdi
callq 0x23240
nop