// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: GPL-3.0-or-later

package ga

// mutation strategies iota consts.

const (
	best1Exp = iota
	rand1Exp
	randtoBest1Exp
)

// mutations.

func clipVals(mutant []float64) []float64 {
	for i := range mutant {
		switch {
		case mutant[i] < 0:
			mutant[i] = 0

		case mutant[i] > 1:
			mutant[i] = 1
		}
	}

	return mutant
}

// mutate performs the mutation of choice and returns the mutant.
func mutate(mutStrategy int, currentIndividual PopulationIndividual, genChamp ChampionIndividual, pop *Population, donors ...PopulationIndividual) []float64 {
	var mutant []float64

	dim := pop.Dimen
	curF := pop.CurF
	champ := genChamp.X
	curX := currentIndividual.CurX

	switch mutStrategy {
	case best1Exp:
		mutant = mutBest1Exp(dim, curF, champ, donors...)

	case rand1Exp:
		mutant = mutRand1Exp(dim, curF, donors...)

	case randtoBest1Exp:
		mutant = mutRandtoBest1Exp(dim, curF, champ, curX, donors...)
	default:
		return nil
	}

	// return mutant with values clipped to <0;1>.
	return clipVals(mutant)
}

func mutBest1Exp(dim int, curF float64, champ []float64, donors ...PopulationIndividual) []float64 {
	mutant := make([]float64, dim)

	for i := 0; i < dim; i++ {
		// mutant[i] = curF + (bestF*(donors[1].CurX[i]) - donors[2].CurX[i])
		mutant[i] = champ[i] + (curF*(donors[1].CurX[i]) - donors[2].CurX[i])
	}

	return mutant
}

func mutRand1Exp(dim int, curF float64, donors ...PopulationIndividual) []float64 {
	mutant := make([]float64, dim)

	for i := 0; i < dim; i++ {
		// tmp[n] = popold[r1][n] + curF*(popold[r2][n]-popold[r3][n]);
		mutant[i] = donors[0].CurX[i] + curF*(donors[1].CurX[i]-donors[2].CurX[i])
	}

	return mutant
}

func mutRandtoBest1Exp(dim int, curF float64, champ, currentIndividual []float64, donors ...PopulationIndividual) []float64 {
	mutant := make([]float64, dim)

	for i := 0; i < dim; i++ {
		mutant[i] += currentIndividual[i] + (curF*champ[i] - currentIndividual[i]) + (curF * (donors[0].CurX[i] - donors[1].CurX[i]))
	}

	return mutant
}
