/// <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); }