/// <summary>
        /// Computes the maximum descent possible from the vector x in the direction dir.
        /// </summary>
        /// <param name="func">Function to find it the greatest descent possible in the given direction.</param>
        /// <param name="x">Current vector of the minimization Quasi-Newton algorithm.</param>
        /// <param name="dir">Descent direction vector for the current vector.</param>
        /// <returns>The value of the maximum descent possible.</returns>
        public static double Wolfe(CompiledFunc func, Vector x, Vector dir)
        {
            double a = 0;
            double ai = 1;
            double fPrev = 0, fCurr = 0, diff = 0;

            double fZero = func.Eval(x);
            var normDir = dir.Normalize();

            double diffZero = (func.Differentiate(x)*normDir).Sum();

            while(ai < MaxAlpha)
            {
                fPrev = func.Eval(x + a*dir);
                fCurr = func.Eval(x + ai*dir);

                if (fCurr > fZero + C1*ai*diffZero || (fCurr > fPrev && ai > 1))
                    return Zoom(func, x, dir, a, ai, fZero, diffZero);

                diff = (func.Differentiate(x + ai*dir)*normDir).Sum();

                if (Math.Abs(diff) <= -C2*diffZero)
                    return ai;

                if (diff >= 0)
                    return Zoom(func, x, dir, ai, a, fZero, diffZero);

                a = ai;
                ai *= 1.5;
            }

            return ai;
        }
        private static double Zoom(CompiledFunc func, Vector x, Vector dir, double aLow, double aHigh, double fZero, double diffZero)
        {
            var normDir = dir.Normalize();
            double aMid = 0;
            double fValue = 0;
            double diff = 0;

            while (Math.Abs(aLow - aHigh) > EPS)
            {
                aMid = aLow + (aHigh - aLow)/2;
                fValue = func.Eval(x + aMid*dir);

                if (fValue > fZero + C1*aMid*diffZero || fValue >= func.Eval(x + aLow*dir))
                    aHigh = aMid;
                else
                {
                    diff = (func.Differentiate(x + aMid*dir)*normDir).Sum();

                    if (Math.Abs(diff) <= -C2*diffZero)
                        return aMid;

                    if (diff*(aHigh - aLow) >= 0)
                        aHigh = aLow;

                    aLow = aMid;
                }
            }

            return aMid;
        }
        protected override Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null)
        {
            SeedPopulation(f, bounds);

            if (x != null)
            {
                double fit = f.Eval(x);

                if (fit < GlobalBestFit)
                {
                    GlobalBestFit = fit;
                    GlobalBestPosition = x;
                    ParticlesSet[0].BestFit = GlobalBestFit;
                    ParticlesSet[0].BestPosition = GlobalBestPosition;
                }
            }

            while (CurrentIteration < IterationsNumber)
            {
                CurrentIteration++;

                foreach (var particle in ParticlesSet)
                {
                    particle.Update();

                    if (particle.BestFit < GlobalBestFit)
                    {
                        GlobalBestFit = particle.BestFit;
                        GlobalBestPosition = particle.BestPosition;
                    }
                }
            }
            return GlobalBestPosition;
        }
        protected override Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null)
        {
            CurrentIteration = 0;
            var b = Matrix.Identity(x.Length);

            var x1 = new Vector(x);
            Vector d;
            double a;

            while (CurrentIteration < IterationsNumber)
            {
                CurrentIteration++;

                d = -b.Dot(f.Differentiate(x));

                a = Searcher(f, x, d);
                x1 = x + a*d;

                b = Corrector(f, b, x, x1);

                if (!Algebra.IsValid(x1) || Algebra.Norm(x1 - x) <= EPS)
                    break;

                x = x1;
            }

            return x;
        }
        /// <summary>
        /// Computes the BFGS correction formula for inverse hessiana approximation.
        /// </summary>
        /// <param name="func">Function to find it the hessiana approximation.</param>
        /// <param name="b">Current inverse approximation of the hessiana.</param>
        /// <param name="x">Current vector of the minimization Quasi-Newton algorithm.</param>
        /// <param name="x1">Next vector of the minimization Quasi-Newton algorithm.</param>
        /// <returns>Returns a matrix representing the next step in inverse hessiana approximation.s</returns>
        public static Matrix Bfgs(CompiledFunc func, Matrix b, Vector x, Vector x1)
        {
            var sk = new Matrix(x1 - x);
            var yk = new Matrix(func.Differentiate(x1) - func.Differentiate(x));

            var t = b.Dot(sk.Transpose()).Dot(sk).Dot(b)/sk.Dot(b).Dot(sk.Transpose())[0,0];
            var t1 = yk.Transpose().Dot(yk)/yk.Dot(sk.Transpose())[0,0];

            return b - t + t1;
        }
        public Particle(CompiledFunc func, int dimensions, int neighborsNumber, Tuple<Vector, Vector> bounds, Func<double> random)
        {
            Func = func;
            NumberOfDimensions = dimensions;
            Bounds = bounds;
            Neighbors = new Particle[neighborsNumber];

            CurrentPosition = BestPosition = new Vector(Enumerable.Range(0, dimensions).Select(i => random()));
            Velocity = new Vector(Enumerable.Range(0, dimensions).Select(i => random()));

            CurrentFit = BestFit = func.Eval(CurrentPosition);
        }
        /// <summary>
        /// Creates the particle set with non-uniform values and selects an initial best position and best fit 
        /// </summary>
        /// <param name="f">Function to which the minimum will be looking for.</param>
        /// <param name="bounds">Limits of function space search.</param>
        private void SeedPopulation(CompiledFunc f, Tuple<Vector, Vector> bounds)
        {
            CurrentIteration = 0;

            double min = bounds.Item1.Min();
            double max = bounds.Item2.Max();

            var dist = Distributions.ExponentialFunc(1.0 / (min * 2 + max * 2 + 1.5));

            ParticlesSet =
                Enumerable.Range(0, NumberOfParticles)
                    .Select(i => new Particle(f, f.Dimension, NumberOfNeighborsByParticle, bounds, dist)).ToArray();

            int index = -1;
            GlobalBestPosition = new Vector(f.Dimension);

            for (int i = 0; i < GlobalBestPosition.Length; i++)
                GlobalBestPosition[i] = bounds.Item1[i] + (bounds.Item2[i] - bounds.Item1[i])/2;

            GlobalBestFit = f.Eval(GlobalBestPosition);

            for (int i = 0; i < NumberOfParticles; i++)
            {
                if (ParticlesSet[i].IsFeasible() && ParticlesSet[i].BestFit < GlobalBestFit)
                {
                    index = i;
                    GlobalBestFit = ParticlesSet[i].BestFit;
                }

                // Setting particle neighbors
                for (int j = 0; j < NumberOfNeighborsByParticle; j++)
                    ParticlesSet[i].Neighbors[j] = ParticlesSet[(i + 1 + j) % NumberOfParticles];
            }

            if (index == -1)
            {
                ParticlesSet[0].BestPosition = GlobalBestPosition;
                ParticlesSet[0].BestFit = GlobalBestFit;

                return;
            }

            GlobalBestPosition = ParticlesSet[index].BestPosition;
            GlobalBestFit = ParticlesSet[index].BestFit;
        }
 /// <summary>
 /// Algorithmic implementation of optimization model to look for the minimun function value.
 /// </summary>
 /// <param name="f">Function to which the minimum will be looking for.</param>
 /// <param name="x">Optional vector used as started point for the algorithm to look for.</param>
 /// <param name="bounds">Optional limits of function space search.</param>
 /// <returns>Returns the minimun vector found by optimizer.</returns>
 protected abstract Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null);
        /// <summary>
        /// Looks for the vector x that minimizes function f, i.e, vector x such that f(x) &lt;= f(y) for all 
        /// y values in the function search space.
        /// </summary>
        /// <param name="f">Function to which the minimum will be looking for.</param>
        /// <param name="input">Optional vector used as started point for the algorithm to look for.</param>
        /// <param name="bounds">Optional limits of function space search.</param>
        /// <returns>Returns a tuple with the minimun vector found by optimizer and the value of the function in this vector.</returns>
        public Tuple<Vector, double> FindMinimun(CompiledFunc f, Vector input = null, Tuple<Vector, Vector> bounds = null)
        {
            var res = Minimize(f, input, bounds);

            return new Tuple<Vector, double>(res, f.Eval(res));
        }