/// <summary>
        /// Initializes a new instance of the <see cref="RelevanceOfStroke"/> class.
        /// </summary>
        /// <param name="transitions">The transitions</param>
        /// <param name="iterations">The iterations</param>
        public RelevanceOfStroke(Transitions transitions, int iterations = 50)
            : base(transitions)
        {
            this.Iterations = iterations;

            this.CountedWinningProbabilities = DenseVector.Create(
                2,
                i =>
            {
                var w = i == 0 ? MatchPlayer.First : MatchPlayer.Second;
                return(this.Match.Rallies.Count(r => r.Winner == w) /
                       (double)this.Match.Rallies.Count);
            });

            var probabilities = transitions.TransitionProbabilities;
            var start         = MakeStartVector(probabilities.ColumnCount);

            this.WinningProbabilities = Markov.Simulate(probabilities, start, iterations)
                                        .SubVector(probabilities.ColumnCount - 2, 2);

            this.ByScorer = this.ComputeRelevanceOfStroke();

            // Transform relevance of stroke to support plotting
            this.ByStriker = new DenseMatrix(
                this.ByScorer.RowCount,
                this.ByScorer.ColumnCount);

            foreach (var pair in this.ByScorer.EnumerateRowsIndexed())
            {
                var v         = pair.Item2;
                var sourceRow = pair.Item1;

                var targetColumn = sourceRow % 2;
                var targetRow    = sourceRow - targetColumn;

                this.ByStriker.SetColumn(
                    targetColumn,
                    targetRow,
                    v.Count,
                    targetColumn == 0 ? v : DenseVector.OfEnumerable(v.Reverse()));
            }
        }
        /// <summary>
        /// Computes the relevance of stroke.
        /// </summary>
        /// <returns>The relevance of strokes</returns>
        private Matrix <double> ComputeRelevanceOfStroke()
        {
            var probabilities = this.Transitions.TransitionProbabilities;
            var relevance     = new DenseMatrix(probabilities.RowCount - 2, 2);
            var start         = MakeStartVector(probabilities.ColumnCount);

            for (int j = 2; j < probabilities.RowCount - 2; ++j)
            {
                // Compute the relevance for each row in the transition matrix.
                // We can skip the zero rows, because there are no transitions
                // to zero strokes anyway
                for (int k = 0; k < 2; ++k)
                {
                    // and for each win/loose combination. k==0 means the first
                    // player won, k==1 means the second player won.
                    var m = probabilities.Clone();

                    var p = m[j, m.ColumnCount - 2 + k];
                    var d = Delta(p);
                    for (int i = 0; i < m.ColumnCount; ++i)
                    {
                        if (m[j, i] != 0)
                        {
                            m[j, i] = m[j, i] - ((d * m[j, i]) / (1 - p));
                        }
                    }

                    m[j, m.ColumnCount - 2 + k] = p + d;

                    // For even rows, we take the winning probability of the first player,
                    // for odd rows, the probability of the second player.
                    var result = Markov.Simulate(m, start, this.Iterations)[m.ColumnCount - 2 + (j % 2)];
                    var pWin   = this.WinningProbabilities[j % 2];
                    relevance[j, k] = result - pWin;
                }
            }

            return(relevance);
        }