Skip to content

Commit f49271b

Browse files
authored
feat: Add Markov count sample. (#13)
1 parent 92dad01 commit f49271b

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ So far, the following exercises have been covered:
1111
- [Continous maximum](./continuousmax/) – calculates the maximum of a sliding window
1212
- [Floyd](./floyd/) – implements Floyd's cycle-finding "Tortoise and Hare" algorithm
1313
- [Heap](./heap/) – implements a heap from scratch, without using the built-in `container/heap` package
14+
- [Markov count](./markovcount/) – figures out how often states are reached by a Markov chain
1415
- [Radix sort](./radixsort/) – implements radix sort
1516
- [Remove k-th last element](./removekthlastelement/) – removes the k-th last element from a single-linked list
1617
- [Run-length encoding](./runlengthencoding/) – encodes and decodes strings using run-length encoding

markovcount/documentation.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package markovcount figures out how often states are reached by a Markov chain.
2+
package markovcount

markovcount/markovcount.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package markovcount
2+
3+
import "math/rand"
4+
5+
type Transition struct {
6+
From string
7+
To string
8+
Probability float64
9+
}
10+
11+
func Count(
12+
initialState string,
13+
transitions []Transition,
14+
iterations int,
15+
) map[string]int {
16+
transitionResults := map[string]int{}
17+
18+
currentState := initialState
19+
for i := 0; i < iterations; i++ {
20+
nextState := getNextState(currentState, transitions)
21+
22+
if _, ok := transitionResults[nextState]; !ok {
23+
transitionResults[nextState] = 0
24+
}
25+
transitionResults[nextState]++
26+
27+
currentState = nextState
28+
}
29+
30+
return transitionResults
31+
}
32+
33+
func getNextState(
34+
currentState string,
35+
transitions []Transition,
36+
) string {
37+
randomValue := rand.Float64()
38+
39+
for _, transition := range transitions {
40+
if transition.From != currentState {
41+
continue
42+
}
43+
44+
if randomValue <= transition.Probability {
45+
return transition.To
46+
}
47+
48+
randomValue -= transition.Probability
49+
}
50+
51+
panic("no transition found")
52+
}

markovcount/markovcount_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package markovcount_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/thenativeweb/codingcircle/markovcount"
8+
)
9+
10+
func TestCount(t *testing.T) {
11+
t.Run("calculates the counts", func(t *testing.T) {
12+
transitions := []markovcount.Transition{
13+
{From: "a", To: "a", Probability: 0.9},
14+
{From: "a", To: "b", Probability: 0.075},
15+
{From: "a", To: "c", Probability: 0.025},
16+
{From: "b", To: "a", Probability: 0.15},
17+
{From: "b", To: "b", Probability: 0.8},
18+
{From: "b", To: "c", Probability: 0.05},
19+
{From: "c", To: "a", Probability: 0.25},
20+
{From: "c", To: "b", Probability: 0.25},
21+
{From: "c", To: "c", Probability: 0.5},
22+
}
23+
24+
result := markovcount.Count("a", transitions, 10_000)
25+
26+
assert.GreaterOrEqual(t, result["a"], 5_700)
27+
assert.LessOrEqual(t, result["a"], 6_800)
28+
29+
assert.GreaterOrEqual(t, result["b"], 2_700)
30+
assert.LessOrEqual(t, result["b"], 3_600)
31+
32+
assert.GreaterOrEqual(t, result["c"], 400)
33+
assert.LessOrEqual(t, result["c"], 900)
34+
})
35+
}

0 commit comments

Comments
 (0)