# markov.tcl -- # Simple implementation of Markov chains as a model for stochastic # processes # namespace eval ::markov { namespace export makeMarkov } # makeMarkov -- # Create a command that behaves as a Markov chain # # Arguments: # name Name of the command # matrix Matrix of transition probabities (list of lists) # init Initial value # # Result: # Name of the command # # Side effect: # A new command is generated that returns a new state at each call # # Note: # There is NO argument checking whatsoever in this simple # implementation # proc ::markov::makeMarkov {name matrix init} { interp alias {} $name {} ::markov::MarkovImpl $name $matrix $name $init return $name } # MarkovImpl -- # Determine a new state for the given Markov chain # # Arguments: # name Name of the command # matrix Matrix of transition probabities (list of lists) # init Initial value (optional, to reset) # # Result: # New state # # Side effect: # The state of the chain is updated # proc ::markov::MarkovImpl {name matrix {init {}}} { variable state_$name # # (Re)initialise or determine the next state via the # transition matrix # if { $init != {} } { set state_$name $init } else { set probabilities [lindex $matrix [set state_$name]] set prob [expr {rand()}] set next 0 foreach trans $probabilities { if { $prob < $trans } { break } else { set prob [expr {$prob-$trans}] incr next } } # # Simple precaution - "should not be necessary" # if { $next >= [llength $probabilities] } { set next 0 } set state_$name $next } return [set state_$name] } # # Demonstration: a traffic light # if { [file tail [info script]] == [file tail $::argv0] } { # # The state changes from 0 to 1 to 2, but may remain the # same for a while. # The numbers in each row must add up to 1. # ::markov::makeMarkov light { {0.8 0.2 0.0} {0.0 0.2 0.8} {0.3 0.0 0.7} } 0 for { set i 0 } { $i < 20 } { incr i } { puts [light] } puts "Counting the states' frequencies:" set count(0) 0 set count(1) 0 set count(2) 0 for { set i 0 } { $i < 2000 } { incr i } { incr count([light]) } puts "State 0: $count(0)" puts "State 1: $count(1)" puts "State 2: $count(2)" }
See also: Finite state machines, Markov, Markov algorithms