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

package bench

import "math"

// Functions is a string-func map of function names and specific bench funcs
// for easier iterable access.
var Functions = map[string]func([]float64) float64{
	"Schwefel":    Schwefel,
	"De Jong 1st": DeJong1st,
	"De Jong 2nd": DeJong2nd,
	"Rastrigin":   Rastrigin,
}

// FuncNames represents a numbered list of function name.
var FuncNames = map[int]string{
	0: "Schwefel",
	1: "De Jong 1st",
	2: "De Jong 2nd",
	3: "Rastrigin",
}

// Function params maps function names to their funcParams for easier iterable
// access.
var FunctionParams = map[string]funcParams{
	"Schwefel":    SchwefelParams,
	"De Jong 1st": DeJong1Params,
	"De Jong 2nd": DeJong2Params,
	"Rastrigin":   RastriginParams,
}

// Schwefel computes the value of the Schwefel function for x.
func Schwefel(x []float64) float64 {
	// - Domain is | x_i | < 500
	// - Global minimum at fmin = 0 at x_i = 420.9687
	var sum float64

	for _, val := range x {
		sum += val * math.Sin(math.Sqrt(math.Abs(val)))
	}

	return 418.9829*float64(len(x)) - sum
}

// DeJong1st computes the value of the 1st De Jong function for x.
func DeJong1st(x []float64) float64 {
	var res float64

	for _, val := range x {
		res += math.Pow(val, 2)
	}

	return res
}

// DeJong2nd computes the value of the 2nd De Jong function for x.
func DeJong2nd(x []float64) float64 {
	var res float64

	for _, val := range x {
		res += math.Floor(val)
	}

	return res
}

// Rastrigin computes the value of the Rastrigin function for x.
// ref: https://www.sfu.ca/~ssurjano/rastr.html
func Rastrigin(x []float64) float64 {
	var sum float64

	// dimension of vector x.
	d := float64(len(x))

	for _, xi := range x {
		sum += math.Pow(xi, 2) - 10*(math.Cos(2*math.Pi*xi))
	}

	y := (10 * d) + sum

	return y
}
