public (DihtomiaRectangle first, DihtomiaRectangle second) SplitByMaxSide(GraphicSettings settings = null)
        {
            int splitDimension = GetMaxSide().dimension;

            List <double> firstUp = new List <double>(upperCorner);

            firstUp[splitDimension] = (lowerCorner[splitDimension] / 2 + upperCorner[splitDimension] / 2);
            DihtomiaRectangle first = new DihtomiaRectangle(new List <double>(lowerCorner), firstUp, settings);

            List <double> secondLow = new List <double>(lowerCorner);

            secondLow[splitDimension] = (lowerCorner[splitDimension] / 2 + upperCorner[splitDimension] / 2);
            DihtomiaRectangle second = new DihtomiaRectangle(secondLow, new List <double>(upperCorner), settings);

            return(first, second);
        }
        public static (double FunctionMinimum, int counter, int optimal, List <double> optimalPoint) Solve(OptimizingFunction function, LipzitsFunction lipzits, double precision, double epsilon, List <double> lowerBound, List <double> upperBound, RuleD rule, GraphicSettings settings = null)
        {
            double lipConst = lipzits(epsilon);
            LinkedList <DihtomiaRectangle> rectangles = new LinkedList <DihtomiaRectangle>();
            DihtomiaRectangle first = new DihtomiaRectangle(lowerBound, upperBound, settings);

            first.EvalQ(function, lipConst);
            rectangles.AddFirst(first);
            int           counter = 1;
            int           optimal = counter;
            List <double> optimalPoint;
            double        currentMin = Math.Min(function(lowerBound), function(first.center));

            if (function(lowerBound) < function(first.center))
            {
                optimalPoint = new List <double>(lowerBound);
            }
            else
            {
                optimalPoint = new List <double>(first.center);
            }
            if (first.Q >= currentMin - epsilon)
            {
                return(currentMin, counter, optimal, optimalPoint);
            }
            while (rectangles.Count != 0)
            {
                var current  = GetRectangle(rectangles, rule);
                var newRects = current.SplitByMaxSide(settings);
                newRects.first.EvalQ(function, lipConst);
                newRects.second.EvalQ(function, lipConst);
                double funcInFirst  = function(newRects.first.center);
                double funcInSecond = function(newRects.second.center);
                if (currentMin < Math.Min(funcInFirst, funcInSecond))
                {
                    if (newRects.first.Q < (currentMin - epsilon) && newRects.first.GetMaxSide().max >= (2d * precision / lipConst))
                    {
                        rectangles.AddFirst(newRects.first);
                    }
                    if (newRects.second.Q < (currentMin - epsilon) && newRects.second.GetMaxSide().max >= (2d * precision / lipConst))
                    {
                        rectangles.AddFirst(newRects.second);
                    }
                }
                else
                {
                    if (funcInFirst < funcInSecond)
                    {
                        currentMin = funcInFirst;
                        rectangles.AddFirst(newRects.first);
                        optimalPoint = new List <double>(newRects.first.center);
                    }
                    else
                    {
                        currentMin = funcInSecond;
                        rectangles.AddFirst(newRects.second);
                        optimalPoint = new List <double>(newRects.second.center);
                    }
                    rectangles.RemoveWorse(currentMin, epsilon);
                    optimal = counter;
                }
                counter++;
            }
            GC.Collect();
            return(currentMin, counter, optimal, optimalPoint);
        }