/// <summary>
        /// Calculates involved partial dependence coefficient of binary chain.
        /// </summary>
        /// <param name="manager">
        /// Intervals manager.
        /// </param>
        /// <param name="link">
        /// Link of intervals in chain.
        /// </param>
        /// <returns>
        /// Involved partial dependence coefficient.
        /// </returns>
        public override double Calculate(BinaryIntervalsManager manager, Link link)
        {
            if (manager.FirstElement.Equals(manager.SecondElement))
            {
                return 0;
            }

            var redundancyCalculator = new Redundancy();

            double redundancy = redundancyCalculator.Calculate(manager, link);

            return redundancy * (2 * manager.PairsCount) / (manager.FirstChain.OccurrencesCount + manager.SecondChain.OccurrencesCount);
        }
        /// <summary>
        /// Calculation method.
        /// </summary>
        /// <param name="manager">
        /// Intervals manager.
        /// </param>
        /// <param name="link">
        /// Link of intervals in chain.
        /// </param>
        /// <returns>
        /// Mutual dependence coefficient
        /// </returns>
        public override double Calculate(BinaryIntervalsManager manager, Link link)
        {
            if (manager.FirstElement.Equals(manager.SecondElement))
            {
                return 0;
            }

            var involvedCoefficientCalculator = new InvolvedPartialDependenceCoefficient();
            double firstInvolvedCoefficient = involvedCoefficientCalculator.Calculate(manager, link);
            double secondInvolvedCoefficient = involvedCoefficientCalculator.Calculate(new BinaryIntervalsManager(manager.SecondChain, manager.FirstChain), link);
            double multipliedInvolvedCoefficient = firstInvolvedCoefficient * secondInvolvedCoefficient;
            return (firstInvolvedCoefficient < 0 || secondInvolvedCoefficient < 0) ? 0 : Math.Sqrt(multipliedInvolvedCoefficient);
        }
        /// <summary>
        /// Calculated as geometric mean between two congeneric sequences.
        /// </summary>
        /// <param name="manager">
        /// Intervals manager.
        /// </param>
        /// <param name="link">
        /// Link of intervals in chain.
        /// </param>
        /// <returns>
        /// Average geometric value.
        /// </returns>
        public override double Calculate(BinaryIntervalsManager manager, Link link)
        {
            // dependence of the component on itself is 0.
            if (manager.FirstElement.Equals(manager.SecondElement))
            {
                return 0;
            }

            int[] intervals = manager.GetIntervals();

            double result = intervals.Where(t => t > 0).Sum(t => Math.Log(t, 2));

            return Math.Pow(2, intervals.Length == 0 ? 0 : result / intervals.Length);
        }
        // TODO: refactor to using intervals manager
        /// <summary>
        /// Calculation method.
        /// </summary>
        /// <param name="manager">
        /// Intervals manager.
        /// </param>
        /// <param name="link">
        /// Link of intervals in chain.
        /// </param>
        /// <returns>
        /// Redundancy as <see cref="double"/>.
        /// </returns>
        public override double Calculate(BinaryIntervalsManager manager, Link link)
        {
            if (manager.FirstElement.Equals(manager.SecondElement))
            {
                return 0;
            }

            var firstElementCount = manager.FirstChain.OccurrencesCount;
            double avG = 0;
            int currentEntrance = 0;

            for (int i = 1; i <= firstElementCount; i++)
            {
                if (manager.GetBinaryInterval(i) > 0)
                {
                    if (currentEntrance == 0)
                    {
                        currentEntrance = manager.GetFirstAfter(manager.GetFirst(i));
                        if (link == Link.Start || link == Link.Both)
                        {
                            avG += Math.Log(currentEntrance, 2);
                        }
                    }
                    else
                    {
                        int nextEntrance = manager.GetFirstAfter(manager.GetFirst(i));
                        avG += Math.Log(nextEntrance - currentEntrance, 2);
                        currentEntrance = nextEntrance;
                    }
                }
            }

            if (link == Link.End || link == Link.Both)
            {
                avG += Math.Log(manager.Length - currentEntrance, 2);
            }

            avG = manager.PairsCount == 0 ? 0 : avG / manager.PairsCount;

            var geometricMeanCalculator = new GeometricMean();
            double binaryGeometricMean = geometricMeanCalculator.Calculate(manager, link);

            return 1 - (binaryGeometricMean / Math.Pow(2, avG));
        }