public static ItemArray <IItem> Apply(IItem initiator, IItem guide, IntValue k, PercentValue n)
        {
            if (!(initiator is RealVector) || !(guide is RealVector))
            {
                throw new ArgumentException("Cannot relink path because one of the provided solutions or both have the wrong type.");
            }
            if (n.Value <= 0.0)
            {
                throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
            }

            RealVector v1 = initiator.Clone() as RealVector;
            RealVector v2 = guide as RealVector;

            if (v1.Length != v2.Length)
            {
                throw new ArgumentException("The solutions are of different length.");
            }

            IList <RealVector> solutions = new List <RealVector>();

            for (int i = 0; i < k.Value; i++)
            {
                RealVector solution = v1.Clone() as RealVector;
                for (int j = 0; j < solution.Length; j++)
                {
                    solution[j] = v1[j] + 1 / (k.Value - i) * (v2[j] - v1[j]);
                }
                solutions.Add(solution);
            }

            IList <IItem> selection = new List <IItem>();

            if (solutions.Count > 0)
            {
                int noSol = (int)(solutions.Count * n.Value);
                if (noSol <= 0)
                {
                    noSol++;
                }
                double stepSize = (double)solutions.Count / (double)noSol;
                for (int i = 0; i < noSol; i++)
                {
                    selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
                }
            }

            return(new ItemArray <IItem>(selection));
        }
        public override IOperation Apply()
        {
            RealVector bestSol = CurrentScope.Variables[SolutionParameter.ActualName].Value as RealVector;

            if (bestSol == null)
            {
                throw new ArgumentException("Cannot improve solution because it has the wrong type.");
            }

            var evaluator = Evaluator;

            double bestSolQuality = evaluator.Evaluate(bestSol);

            // create perturbed solutions
            RealVector[] simplex = new RealVector[bestSol.Length];
            for (int i = 0; i < simplex.Length; i++)
            {
                simplex[i]     = bestSol.Clone() as RealVector;
                simplex[i][i] += 0.1 * (Bounds[0, 1] - Bounds[0, 0]);
                if (simplex[i][i] > Bounds[0, 1])
                {
                    simplex[i][i] = Bounds[0, 1];
                }
                if (simplex[i][i] < Bounds[0, 0])
                {
                    simplex[i][i] = Bounds[0, 0];
                }
            }

            // improve solutions
            for (int i = 0; i < ImprovementAttempts.Value; i++)
            {
                // order according to their objective function value
                Array.Sort(simplex, (x, y) => evaluator.Evaluate(x).CompareTo(evaluator.Evaluate(y)));

                // calculate centroid
                RealVector centroid = new RealVector(bestSol.Length);
                foreach (var vector in simplex)
                {
                    for (int j = 0; j < centroid.Length; j++)
                    {
                        centroid[j] += vector[j];
                    }
                }
                for (int j = 0; j < centroid.Length; j++)
                {
                    centroid[j] /= simplex.Length;
                }

                // reflection
                RealVector reflectionPoint = new RealVector(bestSol.Length);
                for (int j = 0; j < reflectionPoint.Length; j++)
                {
                    reflectionPoint[j] = centroid[j] + Alpha.Value * (centroid[j] - simplex[simplex.Length - 1][j]);
                }
                double reflectionPointQuality = evaluator.Evaluate(reflectionPoint);
                if (evaluator.Evaluate(simplex[0]) <= reflectionPointQuality &&
                    reflectionPointQuality < evaluator.Evaluate(simplex[simplex.Length - 2]))
                {
                    simplex[simplex.Length - 1] = reflectionPoint;
                }

                // expansion
                if (reflectionPointQuality < evaluator.Evaluate(simplex[0]))
                {
                    RealVector expansionPoint = new RealVector(bestSol.Length);
                    for (int j = 0; j < expansionPoint.Length; j++)
                    {
                        expansionPoint[j] = centroid[j] + Beta.Value * (reflectionPoint[j] - centroid[j]);
                    }
                    simplex[simplex.Length - 1] = evaluator.Evaluate(expansionPoint) < reflectionPointQuality ? expansionPoint : reflectionPoint;
                }

                // contraction
                if (evaluator.Evaluate(simplex[simplex.Length - 2]) <= reflectionPointQuality &&
                    reflectionPointQuality < evaluator.Evaluate(simplex[simplex.Length - 1]))
                {
                    RealVector outsideContractionPoint = new RealVector(bestSol.Length);
                    for (int j = 0; j < outsideContractionPoint.Length; j++)
                    {
                        outsideContractionPoint[j] = centroid[j] + Gamma.Value * (reflectionPoint[j] - centroid[j]);
                    }
                    if (evaluator.Evaluate(outsideContractionPoint) <= reflectionPointQuality)
                    {
                        simplex[simplex.Length - 1] = outsideContractionPoint;
                        if (evaluator.Evaluate(reflectionPoint) >= evaluator.Evaluate(simplex[simplex.Length - 1]))
                        {
                            RealVector insideContractionPoint = new RealVector(bestSol.Length);
                            for (int j = 0; j < insideContractionPoint.Length; j++)
                            {
                                insideContractionPoint[j] = centroid[j] - Gamma.Value * (reflectionPoint[j] - centroid[j]);
                            }
                            if (evaluator.Evaluate(insideContractionPoint) < evaluator.Evaluate(simplex[simplex.Length - 1]))
                            {
                                simplex[simplex.Length - 1] = insideContractionPoint;
                            }
                        }
                    }
                }

                // reduction
                for (int j = 1; j < simplex.Length; j++)
                {
                    for (int k = 0; k < simplex[j].Length; k++)
                    {
                        simplex[j][k] = simplex[0][k] + Delta.Value * (simplex[j][k] - simplex[0][k]);
                    }
                }
            }

            for (int i = 0; i < simplex[0].Length; i++)
            {
                if (simplex[0][i] > Bounds[0, 1])
                {
                    simplex[0][i] = Bounds[0, 1];
                }
                if (simplex[0][i] < Bounds[0, 0])
                {
                    simplex[0][i] = Bounds[0, 0];
                }
            }

            CurrentScope.Variables[SolutionParameter.ActualName].Value = simplex[0];
            CurrentScope.Variables.Add(new Variable("LocalEvaluatedSolutions", ImprovementAttempts));

            return(base.Apply());
        }