// File: /workspace/github_cpp_makefile_star2_O2/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 0x82c9d
movl %edx, %ebp
movq 0xe3319(%rip), %rdi     # 0x165f98
leaq 0x5ccf0(%rip), %rsi     # 0xdf976
callq 0x289f0
movl %ebp, %esi
movq %rax, %rdi
callq 0x286e0
movq %rax, %rdi
callq 0x284a0
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
andq $0x0, 0x10(%rbx)
movl 0x1620(%r14), %edx
leaq 0x20(%rsp), %rdi
pushq $0x1
popq %rsi
callq 0x8678c
movl 0x1700(%r14), %eax
decl %eax
cmpl $0x3, %eax
jbe 0x82cdd
movq %rbx, %rax
addq $0x88, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0x59514(%rip), %rcx     # 0xdc1f8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
cmpq %r15, %rax
je 0x82e3b
movsd 0x20(%rax), %xmm0
ucomisd 0x51d6f(%rip), %xmm0    # 0xd4a80
ja 0x82e3f
movq %rax, %rdi
callq 0x28700
jmp 0x82cfb
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0x82d52
movsd 0x20(%rax), %xmm0
ucomisd 0x51d3d(%rip), %xmm0    # 0xd4a80
jbe 0x82d48
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x28700
jmp 0x82d31
leaq 0x1400(%r14), %rdi
leaq 0x4(%rsp), %rsi
movl %ebp, (%rsi)
callq 0x861e4
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x59fa2
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x82bec
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0x82db0
movsd 0x20(%rax), %xmm0
ucomisd 0x51cdf(%rip), %xmm0    # 0xd4a80
jbe 0x82da6
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x28700
jmp 0x82d8f
leaq 0x1400(%r14), %rdi
leaq 0x4(%rsp), %rsi
movl %ebp, (%rsi)
callq 0x861e4
leaq 0x28(%rsp), %rdi
movq %rax, %rsi
callq 0x59fa2
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x82bec
movq 0x1ac8(%r14), %rax
leaq 0x1ab8(%r14), %r15
xorl %ebp, %ebp
cmpq %r15, %rax
je 0x82e0e
movsd 0x20(%rax), %xmm0
ucomisd 0x51c81(%rip), %xmm0    # 0xd4a80
jbe 0x82e04
movl 0x28(%rax), %ebp
movq %rax, %rdi
callq 0x28700
jmp 0x82ded
leaq 0x1400(%r14), %rdi
leaq 0x4(%rsp), %rsi
movl %ebp, (%rsi)
callq 0x861e4
leaq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x59fa2
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x82bec
xorl %eax, %eax
jmp 0x82e42
movl 0x28(%rax), %eax
leaq 0x1400(%r14), %rdi
leaq 0x4(%rsp), %rsi
movl %eax, (%rsi)
callq 0x861e4
leaq 0x70(%rsp), %rdi
movq %rax, %rsi
callq 0x59fa2
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x82bec
movq %rax, %r14
leaq 0x70(%rsp), %rdi
jmp 0x82e95
movq %rax, %r14
leaq 0x58(%rsp), %rdi
jmp 0x82e95
movq %rax, %r14
leaq 0x28(%rsp), %rdi
jmp 0x82e95
movq %rax, %r14
leaq 0x40(%rsp), %rdi
callq 0x5c44e
jmp 0x82ea5
jmp 0x82ea2
jmp 0x82ea2
jmp 0x82ea2
movq %rax, %r14
movq %rbx, %rdi
callq 0x5c44e
movq %r14, %rdi
callq 0x292f0
nop