Skip to content

Commit ccd8410

Browse files
committed
Add markov chain generator
1 parent fa01a16 commit ccd8410

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

src/pyherc/markov.hy

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
;; -*- coding: utf-8 -*-
2+
;;
3+
;; Copyright (c) 2010-2015 Tuukka Turto
4+
;;
5+
;; Permission is hereby granted, free of charge, to any person obtaining a copy
6+
;; of this software and associated documentation files (the "Software"), to deal
7+
;; in the Software without restriction, including without limitation the rights
8+
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
;; copies of the Software, and to permit persons to whom the Software is
10+
;; furnished to do so, subject to the following conditions:
11+
;;
12+
;; The above copyright notice and this permission notice shall be included in
13+
;; all copies or substantial portions of the Software.
14+
;;
15+
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
;; THE SOFTWARE.
22+
23+
(require pyherc.macros)
24+
(import random)
25+
26+
(defn chain-factory [start-elements elements]
27+
"create factory function that can create markov chain instances"
28+
(fn []
29+
"create generator for chain"
30+
(defn select-next-element [elements-list]
31+
"select element"
32+
(let [[high (max (list-comp upper [#t(element lower upper) elements-list]))]
33+
[value (.randint random 0 high)]
34+
[matches (list-comp element [#t(element lower upper) elements-list]
35+
(> lower value upper))]]
36+
(if matches
37+
(first (.choice random matches))
38+
(first (.choice random elements-list)))))
39+
40+
(setv current-element (select-next-element start-elements))
41+
(setv running true)
42+
(yield current-element)
43+
(while running
44+
(setv next-elements (get elements current-element))
45+
(if next-elements
46+
(setv current-element (select-next-element next-elements))
47+
(setv running false))
48+
(when (not running) (break))
49+
(yield current-element))))
50+

src/pyherc/test/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from pyherc.test.unit.test_library_generator import *
3737
from pyherc.test.unit.test_locations import *
3838
from pyherc.test.unit.test_lunge import *
39+
from pyherc.test.unit.test_markov import *
3940
from pyherc.test.unit.test_metamorphosis import *
4041
from pyherc.test.unit.test_mitosis import *
4142
from pyherc.test.unit.test_movement_mode import *

src/pyherc/test/unit/test_markov.hy

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
;; -*- coding: utf-8 -*-
2+
;;
3+
;; Copyright (c) 2010-2015 Tuukka Turto
4+
;;
5+
;; Permission is hereby granted, free of charge, to any person obtaining a copy
6+
;; of this software and associated documentation files (the "Software"), to deal
7+
;; in the Software without restriction, including without limitation the rights
8+
;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
;; copies of the Software, and to permit persons to whom the Software is
10+
;; furnished to do so, subject to the following conditions:
11+
;;
12+
;; The above copyright notice and this permission notice shall be included in
13+
;; all copies or substantial portions of the Software.
14+
;;
15+
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
;; THE SOFTWARE.
22+
23+
(require archimedes)
24+
(require pyherc.macros)
25+
26+
(import [hamcrest [assert-that is-not :as is-not- is- equal-to
27+
has-length has-items]]
28+
[hypothesis.strategies [integers]]
29+
[pyherc.markov [chain-factory]])
30+
31+
(background infinite-foo-chain
32+
[factory (chain-factory :start-elements [#t("foo" 1 100)]
33+
:elements {"foo" [#t("foo" 1 100)]})]
34+
[chain (factory)])
35+
36+
(fact "first element of chain can be read"
37+
(with-background infinite-foo-chain [chain]
38+
(assert-that (first chain) (is- (equal-to "foo")))))
39+
40+
(fact "taking n elements from infinite chain will not exhaust it"
41+
(variants :n (integers :min-value 2))
42+
(with-background infinite-foo-chain [chain]
43+
(drop n chain)
44+
(assert-that (first chain) (is- (equal-to "foo")))))
45+
46+
(background one-element-chain
47+
[factory (chain-factory :start-elements [#t("foo" 1 100)]
48+
:elements {"foo" []})]
49+
[chain (factory)])
50+
51+
(fact "one element markov chain contains only one element"
52+
(variants :n (integers :min-value 1))
53+
(example :n 1)
54+
(with-background one-element-chain [chain]
55+
(assert-that (list (take 10 chain))
56+
(has-length 1))))
57+
58+
(background flip-flop-chain
59+
[factory (chain-factory :start-elements [#t("flip" 1 100)]
60+
:elements {"flip" [#t("flop" 1 100)]
61+
"flop" [#t("flip" 1 100)]})]
62+
[chain (factory)])
63+
64+
(fact "markov chain can switch between states"
65+
(with-background flip-flop-chain [chain]
66+
(assert-that (first chain) (is- (equal-to "flip")))
67+
(assert-that (first chain) (is- (equal-to "flop")))
68+
(assert-that (first chain) (is- (equal-to "flip")))))
69+
70+
(background foo-bar-baz
71+
[factory (chain-factory :start-elements [#t("foo" 1 33)
72+
#t("bar" 34 66)
73+
#t("baz" 67 100)]
74+
:elements {"foo" [#t("bar" 1 50)
75+
#t("baz" 51 100)]
76+
"bar" [#t("foo" 1 50)
77+
#t("baz" 51 100)]
78+
"baz" [#t("foo" 1 50)
79+
#t("bar" 51 100)]})]
80+
[chain (factory)])
81+
82+
(fact "markov chain can have multiple transitions from single element"
83+
(with-background foo-bar-baz [chain]
84+
(assert-that (take 500 chain)
85+
(has-items "foo" "bar" "baz"))))

0 commit comments

Comments
 (0)