using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using EvoBoat.EvoAlg;

namespace NumTest
{
    using NOP = NumOptProblem<VecSolution<EvoBoat.EvoAlg.Vector, double>>;

    public class CEC15TestProblems
    {
        const double INF = 1.0e99;
        const double EPS = 1.0e-14;
        const double E = 2.7182818284590452353602874713526625;
        const double PI = 3.1415926535897932384626433832795029;

        static Vector[] bias;
        static Vector[] shifts;
        static Vector[] rotates;
        static int[][] shuffles;
        //static int ini_flag, n_flag, func_flag;
        //static int[] cf_numbers = { -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 3, 5 };
        static int cf_num = 10;
        public static NOP[] Problems30D;

        static CEC15TestProblems()
        {
            int func_num = 15;
            bias = new Vector[func_num];
            shifts = new Vector[func_num];
            rotates = new Vector[func_num];
            shuffles = new int[func_num][];
            Problems30D = new NOP[func_num];
            for (int i = 0; i < func_num; i++)
                Problems30D[i] = Problem(i + 1, 30);
        }

        public static NOP Problem(int num, int D)
        {
            if (object.ReferenceEquals(shifts[num - 1], null))
                shifts[num - 1] = LoadShiftData(num, D);
            if (object.ReferenceEquals(shifts[num - 1], null))
                shifts[num - 1] = LoadShiftData(num, D);
            if (object.ReferenceEquals(rotates[num - 1], null))
                rotates[num - 1] = LoadRotateMatrix(num, D);
            if (object.ReferenceEquals(rotates[num - 1], null))
                rotates[num - 1] = LoadRotateMatrix(num, D);
            if (((num >= 6 && num <= 8) || num == 10 || num == 13))
            {
                if (object.ReferenceEquals(shuffles[num - 1], null))
                    shuffles[num - 1] = LoadShuffleData(num, D);
            }
            if (num >= 9)
            {
                if (object.ReferenceEquals(bias[num - 1], null))
                    bias[num - 1] = LoadBiasValue(num, D);
            }
            string name = string.Format("F{0}_{1}D", num, D);
            return new NOP(funs[num - 1], Vector.Create(D, -100), Vector.Create(D, 100), name, num * 100);
        }

        public static Func<Vector, double> fun1 = (x) => CEC14TestProblems.ellips_func(x, shifts[0], rotates[0], 1, 1) + 100;
        public static Func<Vector, double> fun2 = (x) => CEC14TestProblems.bentCigar_func(x, shifts[1], rotates[1], 1, 1) + 200;
        public static Func<Vector, double> fun3 = (x) => CEC14TestProblems.ackley_func(x, shifts[2], rotates[2], 1, 1) + 300;
        public static Func<Vector, double> fun4 = (x) => CEC14TestProblems.rastrigin_func(x, shifts[3], rotates[3], 1, 1) + 400;
        public static Func<Vector, double> fun5 = (x) => CEC14TestProblems.schwefel_func(x, shifts[4], rotates[4], 1, 1) + 500;
        public static Func<Vector, double> fun6 = (x) => CEC14TestProblems.hf01(x, shifts[5], rotates[5], shuffles[5], 1, 1) + 600;
        public static Func<Vector, double> fun7 = (x) => CEC14TestProblems.hf03(x, shifts[6], rotates[6], shuffles[6], 1, 1) + 700;
        public static Func<Vector, double> fun8 = (x) => CEC14TestProblems.hf05(x, shifts[7], rotates[7], shuffles[7], 1, 1) + 800;

        public static Func<Vector, double> fun9 = (x) => cf01(x, shifts[8], rotates[8], bias[8], 1) + 900;
        public static Func<Vector, double> fun10 = (x) => cf02(x, shifts[9], rotates[9], shuffles[9], bias[9], 1) + 1000;
        public static Func<Vector, double> fun11 = (x) => cf03(x, shifts[10], rotates[10], bias[10], 1) + 1100;
        public static Func<Vector, double> fun12 = (x) => cf04(x, shifts[11], rotates[11], bias[11], 1) + 1200;
        public static Func<Vector, double> fun13 = (x) => cf05(x, shifts[12], rotates[12], shuffles[12], bias[12], 1) + 1300;
        public static Func<Vector, double> fun14 = (x) => cf06(x, shifts[13], rotates[13], bias[13], 1) + 1400;
        public static Func<Vector, double> fun15 = (x) => cf07(x, shifts[14], rotates[14], bias[14], 1) + 1500;
        public static Func<Vector, double>[] funs = { fun1, fun2, fun3, fun4, fun5, fun6, fun7, fun8, fun9, fun10, fun11, fun12, fun13, fun14, fun15 };

        static Vector LoadRotateMatrix(int num, int D)
        {
            double[] array;
            string[] lines = File.ReadLines(string.Format("testproblems\\cec15data\\M_{0}_D{1}.txt", num, D)).ToArray();
            if (num < 9)
            {
                array = new double[D * D];
            }
            else
            {
                //int cf_num = cf_numbers[num - 1];
                array = new double[D * D * cf_num];
            }
            for (int i = 0, p = 0; i < lines.Length; i++)
            {
                string[] ss = lines[i].Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                for (int j = 0; j < ss.Length; j++)
                    array[p++] = double.Parse(ss[j].Trim());
            }
            return new Vector(array);
        }

        static Vector LoadBiasValue(int num, int D)
        {
            int cf_num = 10;
            double[] array = new double[cf_num];
            string[] lines = File.ReadLines(string.Format("testproblems\\cec15data\\bias_{0}.txt", num)).ToArray();
            for (int i = 0, p = 0; i < lines.Length; i++)
            {
                string[] ss = lines[i].Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                for (int j = 0; j < ss.Length; j++)
                    array[p++] = double.Parse(ss[j].Trim());
            }
            return new Vector(array);
        }


        static Vector LoadShiftData(int num, int D)
        {
            double[] array;
            string s = File.ReadAllText(string.Format("testproblems\\cec15data\\shift_data_{0}.txt", num));
            string[] ss;
            if (num < 9)
            {
                array = new double[D];
                ss = s.Trim().Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < array.Length; i++)
                    array[i] = double.Parse(ss[i].Trim());
            }
            else
            {
                //int cf_num = cf_numbers[num - 1];
                array = new double[D * cf_num];
                ss = s.Trim().Split(new Char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                string[] sss;
                for (int j = 0; j < cf_num; j++)
                {
                    sss = ss[j].Trim().Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    for (int i = 0; i < D; i++)
                        array[j * D + i] = double.Parse(sss[i].Trim());
                }
            }
            return new Vector(array);
        }

        static int[] LoadShuffleData(int num, int D)
        {
            int[] array = null;
            string s = File.ReadAllText(string.Format("testproblems\\cec15data\\shuffle_data_{0}_D{1}.txt", num, D));
            string[] ss = s.Trim().Split(new Char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries);
            if (num >= 6 && num <= 8)
            {
                array = new int[D];
                for (int i = 0; i < ss.Length; i++)
                    array[i] = int.Parse(ss[i].Trim());
            }
            else if (num == 10 || num == 13)
            {
                //int cf_num = cf_numbers[num - 1];
                array = new int[D * cf_num];
                for (int i = 0; i < ss.Length; i++)
                    array[i] = int.Parse(ss[i].Trim());
            }
            return array;
        }

        public static double cf_cal(Vector x, Vector Os, double[] delta, Vector bias, double[] fit, int cf_num)
        {
            double w_max = 0, w_sum = 0, r = 0;
            double[] w = new double[cf_num];
            for (int i = 0; i < cf_num; i++)
            {
                fit[i] += bias[i];
                w[i] = 0;
                for (int j = 0; j < x.Length; j++)
                {
                    w[i] += (x[j] - Os[i * x.Length + j]) * (x[j] - Os[i * x.Length + j]);
                }
                if (w[i] != 0)
                    w[i] = Math.Pow(1.0 / w[i], 0.5) * Math.Exp(-w[i] / 2.0 / x.Length / delta[i] / delta[i]);
                else
                    w[i] = INF;
                if (w[i] > w_max)
                    w_max = w[i];
            }
            for (int i = 0; i < cf_num; i++)
            {
                w_sum = w_sum + w[i];
            }
            if (w_max == 0)
            {
                for (int i = 0; i < cf_num; i++)
                    w[i] = 1;
                w_sum = cf_num;
            }
            for (int i = 0; i < cf_num; i++)
            {
                r = r + w[i] / w_sum * fit[i];
            }
            return r;
        }

        public static double cf01(Vector x, Vector Os, Vector Mr, Vector bias, int r_flag)
        {
            int i, cf_num = 3;
            double r = 0;
            double[] fit = new double[3];
            double[] delta = { 20, 20, 20 };

            i = 0;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(x.Length), Mr.SubVector(x.Length * x.Length), 1, 0);
            i = 1;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            i = 2;
            fit[i] = CEC14TestProblems.hgbat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf02(Vector x, Vector Os, Vector Mr, int[] SS, Vector bias, int r_flag)
        {
            int i, cf_num = 3;
            double r = 0;
            double[] fit = new double[3];
            double[] delta = { 10, 30, 50 };

            i = 0;
            fit[i] = CEC14TestProblems.hf01(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), SS, 1, r_flag);
            i = 1;
            int[] tSS = SS.Skip(i * x.Length).Take(x.Length).ToArray();
            fit[i] = CEC14TestProblems.hf02(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), tSS, 1, r_flag);
            i = 2;
            tSS = SS.Skip(i * x.Length).Take(x.Length).ToArray();
            fit[i] = CEC14TestProblems.hf03(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), tSS, 1, r_flag);
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf03(Vector x, Vector Os, Vector Mr, Vector bias, int r_flag)
        {
            int i, cf_num = 5;
            double r = 0;
            double[] fit = new double[5];
            double[] delta = { 10, 10, 10, 20, 20 };

            i = 0;
            fit[i] = CEC14TestProblems.hgbat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1000;
            i = 1;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            i = 2;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 4e+3;
            i = 3;
            fit[i] = CEC14TestProblems.weierstrass_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 400;
            i = 4;
            fit[i] = CEC14TestProblems.ellips_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+10;
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf04(Vector x, Vector Os, Vector Mr, Vector bias, int r_flag)
        {
            int i, cf_num = 5;
            double r = 0;
            double[] fit = new double[5];
            double[] delta = { 10, 20, 20, 30, 30 };

            i = 0;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 4e+3;
            i = 1;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            i = 2;
            fit[i] = CEC14TestProblems.ellips_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+10;
            i = 3;
            fit[i] = CEC14TestProblems.escaffer6_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 2e+7;
            i = 4;
            fit[i] = CEC14TestProblems.happycat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf05(Vector x, Vector Os, Vector Mr, int[] SS, Vector bias, int r_flag)
        {
            int i, cf_num = 5;
            double r = 0;
            double[] fit = new double[5];
            double[] delta = { 10, 10, 10, 20, 20 };

            i = 0;
            fit[i] = CEC14TestProblems.hf03(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), SS, 1, r_flag);
            i = 1;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            i = 2;
            int[] tSS = SS.Skip(i * x.Length).Take(x.Length).ToArray();
            fit[i] = CEC14TestProblems.hf01(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), tSS, 1, r_flag);
            i = 3;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 4e+3;
            i = 4;
            fit[i] = CEC14TestProblems.escaffer6_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 2e+7;
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf06(Vector x, Vector Os, Vector Mr, Vector bias, int r_flag)
        {
            int i, cf_num = 7;
            double r = 0;
            double[] fit = new double[7];
            double[] delta = { 10, 20, 30, 40, 50, 50, 50 };

            i = 0;
            fit[i] = CEC14TestProblems.happycat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            i = 1;
            fit[i] = CEC14TestProblems.grie_rosen_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 4e+3;
            i = 2;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 4e+3;
            i = 3;
            fit[i] = CEC14TestProblems.escaffer6_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 2e+7;
            i = 4;
            fit[i] = CEC14TestProblems.ellips_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+10;
            i = 5;
            fit[i] = CEC14TestProblems.bentCigar_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+10;
            i = 6;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 10000 * fit[i] / 1e+3;
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }

        public static double cf07(Vector x, Vector Os, Vector Mr, Vector bias, int r_flag)
        {
            int i, cf_num = 10;
            double r = 0;
            double[] fit = new double[10];
            double[] delta = { 10, 10, 20, 20, 30, 30, 40, 40, 50, 50 };

            i = 0;
            fit[i] = CEC14TestProblems.rastrigin_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1e+3;
            i = 1;
            fit[i] = CEC14TestProblems.weierstrass_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 400;
            i = 2;
            fit[i] = CEC14TestProblems.happycat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1e+3;
            i = 3;
            fit[i] = CEC14TestProblems.schwefel_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 4e+3;
            i = 4;
            fit[i] = CEC14TestProblems.rosenbrock_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1e+5;
            i = 5;
            fit[i] = CEC14TestProblems.hgbat_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1000;
            i = 6;
            fit[i] = CEC14TestProblems.katsuura_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1e+7;
            i = 7;
            fit[i] = CEC14TestProblems.escaffer6_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 2e+7;
            i = 8;
            fit[i] = CEC14TestProblems.grie_rosen_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 4e+3;
            i = 9;
            fit[i] = CEC14TestProblems.ackley_func(x, Os.SubVector(i * x.Length, x.Length), Mr.SubVector(i * x.Length * x.Length, x.Length * x.Length), 1, r_flag);
            fit[i] = 100 * fit[i] / 1e+5;
            r = cf_cal(x, Os, delta, bias, fit, cf_num);
            return r;
        }
    }
}
