Markov process representation
Scott David Daniels
scott.daniels at acm.org
Wed Mar 15 12:38:23 EST 2006
Here's one way (convert each set of transition percentages to
a running sum up to one):
import random
class SingleStateMarkov(object):
def __init__(self, probabilities, initial=None):
self._states = states = sorted(probabilities)
self._fromstate = dict([(name, n) for n, name in
enumerate(states)])
self._all_states = set(states)
self.transition = dict()
for name, row in probabilities.iteritems():
self.transition[name] = self.add_transitions(name, row)
if initial is None:
initial = self._states[0]
elif initial not in self._all_states:
raise ValueError('Invalid initial state %s' % initial)
self.state = initial
def add_transitions(self, name, row):
if set(row) - self._all_states:
raise ValueError('%s: moves to unknown states %s' % (
name, set(row) - self._all_states))
if min(row.values()) < 0:
raise ValueError('%s: bad odds for states %s' % (name,
[nm for nm,odds in row.iteritems() if odds < 0]))
total = float(sum(row.values())) # Sum of the odds.
if total <= 0:
raise ValueError('%s: No Transitions allowed' % name)
running_total = 0.
cumulative = []
for name in self._states:
running_total += row.get(name, 0.0)
cumulative.append(running_total / total)
return cumulative
def move(self):
v = random.random()
for index, entry in enumerate(self.transition[self.state]):
if v <= entry:
break
self.state = self._states[index]
return self.state
class MultiStateMarkov(SingleStateMarkov):
def __init__(self, probabilities, initial=None, order=2):
if [key for key in probabilities if len(key) != order]:
raise ValueError('State keys wrong size: %s' %
[key for key in probabilities
if len(key) != order])
self._all_states = set()
for i in range(order):
self._all_states |= set(key[i] for key in probabilities)
self._states = states = sorted(self._all_states)
self._fromstate = dict([(name, n) for n, name in
enumerate(states)])
self.transition = dict()
for key, row in probabilities.iteritems():
self.transition[key] = self.add_transitions(key, row)
if initial is None:
initial = (self._states[0],) * order
elif len(initial) != order or set(initial)-self._all_states:
raise ValueError('Invalid initial state %s' % initial)
self.state = initial
def move(self):
v = random.random()
for index, entry in enumerate(self.transition[self.state]):
if v <= entry:
break
state = self._states[index]
self.state = self.state[1:] + (state,)
return state
c = SingleStateMarkov(dict(A=dict(A=20, B=50, C=30),
B=dict(A=35, B=25, C=40),
C=dict(A=70, B=14, C=16)))
d = MultiStateMarkov(dict([(('A', 'A'), dict(A=15, B=55, C=30)),
(('A', 'B'), dict(A=20, B=45, C=35)),
(('A', 'C'), dict(A=60, B=30, C=10)),
(('B', 'A'), dict(A=35, B=25, C=40)),
(('B', 'B'), dict(A=49, B=48, C=3)),
(('B', 'C'), dict(A=60, B=20, C=20)),
(('C', 'A'), dict(A=5, B=75, C=20)),
(('C', 'B'), dict(A=0, B=90, C=10)),
(('C', 'C'), dict(A=70, B=14, C=16))]))
--Scott David Daniels
scott.daniels at acm.org
More information about the Python-list
mailing list