extensions [array] globals [ world-state c-halt-periods-satisfied k-halt-periods-satisfied previous-kl efficiency conv-list conv-time-avgs-list conv-stop eff-list eff-avgs-list eff-stop just-stopped param-list statelist phantom-occurred mid-phantom has-marked mark-ticks ] breed [senders sender] breed [receivers receiver] directed-link-breed [comms comm] senders-own [propensities signal perceived-state firstConverged lastConverged converged kl-converged-periods myReceiver markPropensities oldPropensities ] receivers-own [propensities act perceived-signal firstConverged lastConverged converged kl-converged-periods mySender markPropensities oldPropensities ] to setup ; clear-all clear-all-plots clear-drawing clear-links clear-output clear-patches clear-turtles ; Make all initial values known. output-print word game-type " GAME" output-print notes output-print "PARAMETERS:" output-print "" output-print word "Pairs: " pairs output-print word "States: " states output-print word "Signals: " signals output-print word "Acts: " acts output-print word "Sender-inputs: " sender-inputs output-print word "Receiver-inputs: " receiver-inputs output-print word "Law stdv: " laws-stdv output-print word "Law drift: " laws-drift output-print word "Law surprise: " laws-surprise output-print word "Sender perception stdv: " state-perception-stdv output-print word "Sender experimentation: " sender-experimentation output-print word "Receiver perception stdv: " signal-perception-stdv output-print word "Receiver experimentation: " receiver-experimentation output-print word "Payoff: " payoff output-print word "Penalty: " penalty output-print word "Catastrophe-Frequency: " catastrophe-freq output-print word "Catastrophe-Penalty: " catastrophe-penalty output-print word "Initial Propensity: " propensity-init output-print word "Forgetfulness Interval: " forget-interval output-print word "Forgetfulness: " forgetfulness output-print word "Sender-Receiver Pairs: " pairs output-print word "Convergence Method: " convergenceMethod if ( convergenceMethod = "Maximum Probability" ) [ output-print word "Probability Threshhold: " max-prob-threshold ] if ( convergenceMethod = "KL Divergence" ) [ output-print word "KL Threshhold: " kl-div-threshold ] output-print word "Efficiency Threshold: " efficiency-threshold output-print " " ; initialize the turtles setup-turtles setup-world ; kl-threshold has not been met yet set c-halt-periods-satisfied 0 set k-halt-periods-satisfied 0 ; setting this to a large number just means we won't accidentally 'converge' on the first check set previous-kl 100000 ; efficiency starts at zero set efficiency 0 ; no convergence has occurred yet set conv-stop false set conv-list ( list 0 ) set conv-time-avgs-list ( list 0 ) set eff-stop false set eff-list ( list 0 ) set eff-avgs-list ( list 0 ) ; we did not just stop! set just-stopped false ; we have not marked set has-marked false ; grab the mark-ticks set mark-ticks mark-ticks-max ; don't clear param-list! We need that to be maintained across runs. set statelist n-values states [0] ; the phantom convergence problem...an ugly solution! set phantom-occurred true set mid-phantom false if ( states >= 4 ) [ set phantom-occurred false ] reset-ticks end ; ************* ; SETUP TURTLES ; ************* to setup-turtles ; create pairs of senders and receivers repeat pairs [ ; these variables are defined here so that they are available to the code after the agents are created. let thisSender nobody let thisReceiver nobody ; make a sender create-senders 1 [ ; grab a reference to the sender that we are currently creating (for use when tying it to its receiver, below) set thisSender turtle who ; initialize the propensities set propensities flatPropensities sender-inputs signals propensity-init ; apparently copy-propoensities is required or we just get an array of references to the rows of propensities rather than a true copy set oldPropensities copy-propensities propensities set markPropensities copy-propensities propensities ; signal = -1 means 'no signal has been sent' set signal -1 ; perceived-state = -1 means 'no state has been perceived' set perceived-state -1 ; we have not converged set firstConverged -1 set lastConverged -1 set converged false set kl-converged-periods 0 ; we don't need to see the turtle! hide-turtle ] ; make a receiver create-receivers 1 [ ; grab a reference to the sender that we are currently creating (for use when tying it to its sender, below) set thisReceiver turtle who ; it's helpful to maintain a reference to my sender set mySender thisSender ; initialize the propensities set propensities flatPropensities receiver-inputs acts propensity-init ; use copy-propensities to avoid getting references set oldPropensities copy-propensities propensities set markPropensities copy-propensities propensities ; act = -1 means 'no act has been performed' set act -1 ; perceived-signal = -1 means 'no signal has been perceived' set perceived-signal -1 ; we have not converged set firstConverged -1 set lastConverged -1 set converged false set kl-converged-periods 0 ; we don't need to see the turtle! hide-turtle ] ; tie the two agents together ask thisSender [ set myReceiver thisReceiver create-comm-to thisReceiver [ tie hide-link ] ] ] end ; *********** ; SETUP WORLD ; *********** to setup-world ; choose an initial random state for the world set world-state random states end to go-many ; clear and prepare ;; (for this model to work with NetLogo's new plotting features, ;; __clear-all-and-reset-ticks should be replaced with clear-all at ;; the beginning of your setup procedure and reset-ticks at the end ;; of the procedure.) clear-all ; set showPlots false ; we're going to loop through all of the settings in a list of settings and run the simulation once for each one. ; parse the parameters run parameters ; we now have a list (called param-list); the first item might tell us how to save plots let plotname "plot" if ( not ( is-list? ( item 0 param-list ) ) ) [ set plotname ( item 0 param-list ) set param-list ( but-first param-list ) ] ; the last element is an optional name for exporting the output let outputFile "output" if ( not ( is-list? ( last param-list ) ) ) [ set outputFile ( last param-list ) set param-list ( but-last param-list ) ] ; the remaining elements of param-list are (or better be!) lists; the first element of each is a variable name and the remaining ; elements are the values to be assigned to it for the simulations ; loop through the parameter-values -- there better be the same number of values for each variable or we will die! let i 1 while [ i < ( length ( item 0 param-list ) ) ] [ ; set variables foreach param-list [ run ( word "set " ( item 0 ? ) " " ( item i ? ) ) ] ; setup everything setup ; go until this simulation halts go-loop ; save the results if ( save-results ) [ output-print " " output-print "INEFFICIENT PAIRS:" show-inefficient output-print " " output-print "UNSTABLE AGENTS" show-unconverged output-print " " final-stats export-interface ( word plotname "-" i ".png") export-output (word outputFile "-" i ".txt") ] ; move on to the next one... set i ( i + 1 ) ] end to go-loop loop [ go if ( just-stopped ) [ stop ] ] end ; ************ ; MAIN ROUTINE ; ************ to go if ( ticks = 0 ) [ output-print " " output-print word "START: " date-and-time ] ; if time is up then halt if ( ( timeout > 0 ) and (ticks >= timeout) and ( ( not has-marked ) or ( mark-ticks = 0 ) ) ) [ output-print word "HALT: " date-and-time final-stats set just-stopped true stop ] ; Monitor for various things every convergence-resolution ticks -- these things could trigger a halt if ( ( convergence-resolution > 0 ) and ( remainder ticks convergence-resolution = 0 ) ) [ let stop-now false ; check on threshold convergence if ( ( monitorConv ) or ( convergence-halt-threshold < 100 ) ) [ ifelse ( ( monitor-convergence turtles ) > convergence-halt-threshold ) [ set c-halt-periods-satisfied ( c-halt-periods-satisfied + 1 ) if ( c-halt-periods-satisfied >= halt-periods ) [ set stop-now true ] ] [ set c-halt-periods-satisfied 0 ] ] ; check on kl convergence if ( ( monitorKLDistance ) or ( kl-halt-threshold > 0 ) ) [ let kl monitor-kl turtles ifelse ( ( abs ( kl - previous-kl ) ) < kl-halt-threshold ) [ set k-halt-periods-satisfied ( k-halt-periods-satisfied + 1 ) if ( k-halt-periods-satisfied >= halt-periods ) [ set stop-now true ] ] [ set k-halt-periods-satisfied 0 ] set previous-kl kl ] ; check on overall accuracy if ( ( monitorAccuracy ) or ( accuracy-halt-threshold < 100 ) ) [ if ( ( monitor-accuracy receivers ) > accuracy-halt-threshold ) [ set stop-now true ] ] ; check on overall efficiency of the pairs if ( monitorEfficiency ) [ monitor-efficiency comms ] ; check for conv-stop and eff-stop if ( ( ( conv-stop and conv-time-avg-halt ) and ( eff-stop and eff-time-avg-halt ) ) or ( ( not eff-time-avg-halt ) and ( conv-stop and conv-time-avg-halt ) ) or ( ( not conv-time-avg-halt ) and ( eff-stop and eff-time-avg-halt ) ) ) [ set stop-now true ] ; if we are to halt then do so if ( ( stop-now ) and ( ( not has-marked ) or ( mark-ticks = 0 ) ) ) [ output-print word "HALT: " date-and-time final-stats set just-stopped true stop ] ] ; update mark-ticks if necessary if ( ( has-marked ) and ( mark-ticks > 0 ) ) [ set mark-ticks ( mark-ticks - 1 ) ] ifelse ( game-type = "SIGNAL" ) [ update-world turtles-send turtles-act turtles-learn ] [ ;; if it isn't signal then it's prediction (at least for now...) turtles-send turtles-act update-world turtles-learn ] tick end ; ************ ; SENDERS SEND ; ************ to turtles-send ; senders send a signal to their receivers ask senders [ ; perceive the state ; if the state is not one to which this sender is sensitive, the perceived state is -1 ('null'), as is the signal ifelse ( world-state >= array:length propensities ) [ set perceived-state -1 set signal -1 ] [ ; this conditional is just to improve speed when state-perception-stdv is 0 ifelse ( state-perception-stdv = 0 ) [ set perceived-state world-state ] [ ; Sender perceives a state chosen from a normal distribution whose mean is the current world-state and std dev state-stdv. ; Note that the topology of the state space is a ring -- hence the mod states at the end. set perceived-state ( round ( random-normal world-state state-perception-stdv ) ) mod ( array:length propensities ) ] ; choose a signal based on the perceived state set signal ( selectFromPropensities propensities ( totalPropensity propensities perceived-state ) perceived-state ) ; if we are an experimenter, then put in a perturbation, which just means that we might choose a signal near to this one, and not this one if ( sender-experimentation > 0 ) [ set signal ( round ( random-normal signal sender-experimentation ) ) mod ( array:length ( array:item propensities 0 ) ) ] ] ] end ; ************* ; RECEIVERS ACT ; ************* to turtles-act ; receivers retrieve the message and choose an act ; What to do if a signal is sent that is outside the 'ken' of the receiver? For now, receiver does nothing (act = -1) ; It might be interesting to change this behavior. NB: if you do, be sure to revise the pairAccuracy and the ; probForOutcome procedures! ask receivers [ ; perceive the signal sent by mySender ifelse ( ( ( [signal] of mySender ) = -1 ) or ( ( [signal] of mySender ) >= ( array:length propensities ) ) ) [ set perceived-signal -1 set act -1 ] [ ; this conditional is just to improve speed when signal-perception-stdv is 0 ifelse ( signal-perception-stdv = 0 ) [ set perceived-signal ( [signal] of mySender ) ] [ ; Receiver perceives a state chosen from a normal distribution whose mean is the current signal of the sender and std dev signal-perception-stdv. ; Note that the topology of the signal space is a ring -- hence the mod signals at the end. set perceived-signal ( round ( random-normal ( [signal] of mySender ) signal-perception-stdv ) ) mod ( array:length propensities ) ] ; choose an act based on the perceived signal set act ( selectFromPropensities propensities ( totalPropensity propensities perceived-signal ) perceived-signal ) if ( receiver-experimentation > 0 ) [ ; that last mod acts should probably be redone in terms of array-length set act ( round ( random-normal act receiver-experimentation ) ) mod ( array:length ( array:item propensities perceived-signal ) ) ] ] ] end ; ************ ; UPDATE WORLD ; ************ to update-world ifelse ( ( laws-surprise > 0 ) and ( does-prob-occur laws-surprise ) ) [ ; surprise! Choose a random state set world-state ( random states ) ] [ ; The next state of the world is chosen from a normal distribution whose mean is the current state of the world and std dev laws-stdv. ; Note that the topology of the state space is a ring -- hence the mod states at the end. set world-state ( round ( (random-normal world-state laws-stdv) + laws-drift) ) mod states ] ; uncomment for having a look at the distribution of states over the course of the game set statelist ( replace-item world-state statelist ( ( item world-state statelist ) + 1 ) ) end ; ************* ; TURTLES LEARN ; ************* to turtles-learn ask receivers [ ; Did we predict the state correctly? ifelse ( act = world-state ) [ ; Yes! So reward both sender and receiver ; note that we don't need to worry about negative values here because (at least as things stand now) we cannot succeed in that case array:set (array:item propensities perceived-signal) act ( (array:item (array:item propensities perceived-signal) act ) + payoff ) ask mySender [ array:set (array:item propensities perceived-state) signal ( (array:item (array:item propensities perceived-state) signal ) + payoff ) ] ] [ ; No! So penalize both sender and receiver ; is it a catastrophe? let penalize penalty if ( does-prob-occur catastrophe-freq ) [ set penalize catastrophe-penalty ] ; if there is no perceived signal then the receiver cannot learn anything from this failure if ( perceived-signal >= 0 ) [ array:set (array:item propensities perceived-signal) act ( (array:item (array:item propensities perceived-signal) act ) - penalize ) if ( ( array:item (array:item propensities perceived-signal) act ) < minimum-propensity ) [ array:set (array:item propensities perceived-signal) act minimum-propensity ] ] ask mySender [ ; similarly, if there is no perceived state then the sender cannot learn anything from this failure if ( perceived-state >= 0 ) [ array:set (array:item propensities perceived-state) signal ( (array:item (array:item propensities perceived-state) signal ) - penalize ) if ( ( array:item (array:item propensities perceived-state) signal ) < minimum-propensity ) [ array:set (array:item propensities perceived-state) signal minimum-propensity ] ] ] ] ; apply forgetting if ( ( forget-interval > 0 ) and ( ( ticks mod forget-interval ) = 0 ) ) [ scalePropensities self forgetfulness ask mySender [ scalePropensities self forgetfulness ] ] ] end ; ************************************ ; CHOOSE TRUE (ELSE FALSE) WITH PROB p ; ************************************ ; if p is smaller than 10 ^ 9 then this will not work to-report does-prob-occur [ p ] let r false let target p * ( 10 ^ 9 ) if ( ( random ( 10 ^ 9 ) ) < target ) [ set r true ] report r end ; ***************** ; CHECK CONVERGENCE ; ***************** ; ; Branch to the appropriate convergence checker; return false if we don't recognize it! to-report isConverged [ agent ] if ( convergenceMethod = "Maximum Probability") [ report max-prob-convergence agent ] if ( convergenceMethod = "KL Divergence") [ report kl-convergence agent ] report false end ; ************** ; KL CONVERGENCE ; ************** ; ; We are 'converged' if the KL divergence from our previous self isn't too big and has been that way long enough to-report kl-convergence [ agent ] let c false ask agent [ ifelse ( ( mean-kl-divergence ( propensityArray2disposition propensities) ( propensityArray2disposition oldPropensities ) ) < kl-div-threshold ) [ ; increment kl-converged-periods set kl-converged-periods ( kl-converged-periods + 1 ) ; if we've been under the threshold for kl-div-threshold-periods minus 1 then we are now converged if ( kl-converged-periods >= kl-div-threshold-periods ) [ set c true ] ] [ ; kl-converged-periods must start again from scratch... set kl-converged-periods 0 ] ; we manage oldPropensities here because we need to be keeping track of it only ; if the convergence method is KL-divergence, and we need to set oldPropensities ; only whenever we have checked for convergence. So here it is. copy-propensities ; is necessary to avoid getting an array of references to the rows of propensities, ; instead of the actual values. set oldPropensities copy-propensities propensities ] report c end ; useful for testing to-report kl-change [ agent ] let c 0 ask agent [ set c ( mean-kl-divergence ( propensityArray2disposition propensities) ( propensityArray2disposition oldPropensities ) ) ] report c end ; useful for 'hand'testing' certain things. Just fill in the values you need and leave the rest zero and the procedure will do the right thing. to set-agent-propensities [ agent ] let n1 [ 97 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n2 [ 1 97 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n3 [ 1 1 97 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n4 [ 1 1 1 97 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n5 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n6 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n7 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n8 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n9 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n10 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n11 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n12 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n13 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n14 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n15 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n16 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n17 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n18 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n19 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n20 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n21 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n22 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n23 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n24 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n25 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n26 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n27 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n28 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n29 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n30 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n31 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let n32 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let np ( list n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 n15 n16 n17 n18 n19 n20 n21 n22 n23 n24 n25 n26 n27 n28 n29 n30 n31 n32 ) let newp array:from-list np let o1 [ 25 25 25 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o2 [ 25 25 25 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o3 [ 25 25 25 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o4 [ 25 25 25 25 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o5 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o6 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o7 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o8 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o9 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o10 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o11 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o12 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o13 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o14 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o15 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o16 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o17 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o18 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o19 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o20 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o21 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o22 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o23 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o24 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o25 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o26 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o27 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o28 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o29 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o30 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o31 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let o32 [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ] let op ( list o1 o2 o3 o4 o5 o6 o7 o8 o9 o10 o11 o12 o13 o14 o15 o16 o17 o18 o19 o20 o21 o22 o23 o24 o25 o26 o27 o28 o29 o30 o31 o32 ) let oldp array:from-list op ask agent [ let i 0 while [ i < array:length propensities ] [ let j 0 while [ j < ( array:length (array:item propensities i) ) ] [ array:set ( array:item propensities i ) j ( item j (array:item newp i) ) array:set ( array:item oldPropensities i ) j ( item j (array:item oldp i) ) set j ( j + 1 ) ] set i ( i + 1 ) ] ] end ; ********************* ; THRESHOLD CONVERGENCE ; ********************* ; ; A simple convergence checker based on a threshold highest probability to-report max-prob-convergence [ agent ] let c true ask agent [ ; index to the rows of propensities let i 0 while [ i < array:length propensities ] [ ; index into the entries of row i of the propensities let j 0 ; grab a reference to this row for easy access later let thisRow ( array:item propensities i ) ; now look for an entry above max-prob-threshold let unconvergedRow true while [ unconvergedRow and ( j < array:length thisRow ) ] [ if ( ( 100 * ( ( array:item thisRow j ) / ( totalPropensity propensities i ) ) ) > max-prob-threshold ) [ set unconvergedRow false ] ; increment entry index set j ( j + 1 ) ] if ( unconvergedRow ) [ ; this row is not converged, and therefore the agent is not set c false stop ] ; increment row index set i ( i + 1 ) ] ] report c end ; ********************************* ; MONITOR STATS RELATED TO ACCURACY ; ********************************* ; Returns the percentage of converged turtles if we did check to-report monitor-accuracy [ ag ] ; determinue accuracy let accuracySum 0 ask ag [ set accuracySum ( accuracySum + ( pairAccuracy self ) ) ] let avgAccuracy ( 100 * ( accuracySum / ( count ag ) ) ) ; update plots if ( showPlots ) [ ; set-current-plot "Accuracy" ; set-current-plot-pen "acc" set-current-plot "Accuracy (green), Efficiency (black), Convergence [stability] (red)" set-current-plot-pen "accuracy" plot avgAccuracy ] report avgAccuracy end ; ********************************************** ; MONITOR STATS RELATED TO THRESHOLD CONVERGENCE ; ********************************************** ; Returns the percentage of converged turtles ; Note that we don't care, here, what convergence method is being used. to-report monitor-convergence [ ag ] ; determine number converged let totalConv 0 ask ag [ let wasConverged converged set converged false ifelse ( isConverged self ) [ set converged true ; if this is our first convergence, record the time ; ugly phantom-convergence fix -- if phantom-occurred is true then we start counting 'first convergence time' if ( ( firstConverged = -1) and phantom-occurred ) [ set firstConverged ticks ] if ( ( not wasConverged ) and phantom-occurred ) [ set lastConverged ticks ] ; update total converged set totalConv ( totalConv + 1 ) ] [ ; we set lastConverged to -1 when we are unconverged to handle the case where ; we converge, then unconverge, and never reconverge. In that case, there is ; no lastConverged time. set lastConverged -1 ] ] let percentConv ( 100 * ( totalConv / count ag ) ) ; now, if anybody has converged and phantom-occurred is false, then we are mid-phantom ifelse ( ( not mid-phantom ) and ( ( not phantom-occurred ) and ( percentConv > 0 ) ) ) [ set mid-phantom true output-print word ticks ": Phantom Begins" ] [ ; on the other hand, if we are mid-phantom and nobody is converged, then the phantom convergence is (we hope!) over if ( mid-phantom ) and ( percentConv = 0 ) [ set phantom-occurred true set mid-phantom false output-print word ticks ": Phantom Ends" ; moreover, if efficiency is high enough, then we stop looking for a phantom convergence if ( ( not phantom-occurred ) and ( efficiency > ( 100 / states ) ) ) [ set phantom-occurred true ] ] ] ; finally, if we are mid-phantom, then nobody is really converged if ( mid-phantom ) [ set percentConv 0 ] ; are we tracking conv time avg? if ( convergence-turning-point > 0 ) [ ; keep track of time-averaged convergence once we pass the turning-point ifelse ( percentConv > convergence-turning-point ) [ ; are we already counting? ifelse ( ( first conv-list ) > 0 ) [ ; we are counting ; add the convergence for this period to the list set conv-list ( lput percentConv conv-list ) ; does that complete an interval of periods? (if not then we're done) if ( ( length conv-list ) >= time-avg-periods ) [ ; interval complete -- have we already added an element to the list of time averages? ifelse ( ( first conv-time-avgs-list ) > 0 ) [ ; yes, so just add this one set conv-time-avgs-list ( lput ( mean conv-list ) conv-time-avgs-list ) ] [ ; no, so this is the first one set conv-time-avgs-list ( list ( mean conv-list ) ) ] ; reset to begin counting again set conv-list ( list 0 ) ; does our list of time-averages exceed the allowed maximum size? if so, cut it down if ( ( length conv-time-avgs-list ) > time-avg-intervals ) [ set conv-time-avgs-list ( but-first conv-time-avgs-list ) ] ; Does the current list of time averages satisfy the halting conditions? ifelse ( conv-time-avg-halt and ( ( ( length conv-time-avgs-list ) >= time-avg-intervals ) and ( ( standard-deviation conv-time-avgs-list ) < convergence-stability-threshold ) ) ) [ set conv-stop true ] [ ; when multiple criteria are in play for stopping, the convergence criterion could get met, then 'unmet'. ; We choose to turn stopping off in this case and require the condition to be met again. set conv-stop false ] ] ] [ ; we are beginning a new interval of time-averaged periods ; record percentConv as the first value in the new interval set conv-list ( list percentConv ) ] ] [ ; this block is necessary in case we go above the turning-point then dip back down, in which case we reset everything set conv-list ( list 0 ) set conv-time-avgs-list (list 0 ) ] ] ; update plots if ( showPlots ) [ ; set-current-plot "Converged" ; set-current-plot-pen "percentConv" set-current-plot "Accuracy (green), Efficiency (black), Convergence [stability] (red)" set-current-plot-pen "convergence" plot percentConv ] ; return percentage converged report percentConv end ; *************************************** ; MONITOR STATS RELATED TO KL CONVERGENCE ; *************************************** ; ; Returns the mean mean kl-divergence from determinism to-report monitor-kl [ ag ] ; get mean mean kl-distance from determinism let meanKL 0 if ( monitorKLDistance ) [ let mkl 0 ; determine mean kl-divergence amongst all agents ask ag [ set mkl ( mkl + ( mean-kl-divergence-from-determinism propensities ) ) ] set meanKL ( mkl / count ag ) ] ; update plots if ( showPlots ) [ set-current-plot "Mean-Mean-KL Divergence from Determinism" set-current-plot-pen "meanKL" ifelse ( monitorKLDistance ) [ plot-pen-down ] [ plot-pen-up ] plot meanKL set-current-plot-pen "meanKLInactive" ifelse ( monitorKLDistance ) [ plot-pen-up ] [ plot-pen-down ] plot meanKL ] ; return mean mean KL report meanKL end ; ***************************************************************** ; DETERMINE THE MAXIMUM NUMBER OF INPUTS THAT AN AGENT CAN PERCEIVE ; ***************************************************************** to-report maxInputs [ agent ] let maxin 0 ; senders will have either states inputs or the length of their disposition, whichever is LESS if ( is-sender? agent ) [ set maxin min ( list ( array:length ( [propensities] of agent ) ) ( states ) ) ] ; receivers can have (at most) the most that the sender can send, or the length of their disposition, whichever is LESS if ( is-receiver? agent ) [ set maxin min ( list ( array:length [propensities] of agent ) ( maxOutputs ([mySender] of agent) ) ) ] report maxin end ; ***************************************************************** ; DETERMINE THE MAXIMUM NUMBER OF OUTPUTS THAT AN AGENT CAN PRODUCE ; ***************************************************************** to-report maxOutputs [ agent ] report array:length ( array:item ( [propensities] of agent ) 0 ) end ; ******************************************************************************* ; DETERMINE THE MAXIMUM NUMBER OF OUTPUTS THAT A PAIR COULD POSSIBLY DISTINCGUISH ; ******************************************************************************* ; the receiver represents the pair -- WE DO NOT CHECK THAT r IS A RECEIVER! to-report max-outputs-for-pair [ r ] ; the most inputs that a pair can be expected to distinguish ; just depends on where the 'bottleneck', if any, is let m 0 ask r [ set m min ( list ( maxInputs mySender ) ( maxOutputs mySender ) ( maxInputs self ) (maxOutputs self ) ) ] report m end ; *********************************************** ; DETERMINE WHETHER A PAIR OF AGENTS IS EFFICIENT ; *********************************************** ; a pair of agent is 'efficient' iff as many outcomes as possible have some input or set of inputs ; (if sender is playing a mixed strategy) that gives it probability greater than efficiency-threshold ; ; note that s does not have to be the mySender of r (but typically would be). to-report isPairEfficient [ s r ] ; how many outcomes SHOULD we be able to distinguish? let target ( max-outputs-for-pair r ) ; a count of efficiently produced outcomes let efficientOutcomes 0 ask r [ ; the highest numbered outcome we can even in principle produce let highest ( ( array:length ( array:item propensities 0 ) ) - 1 ) let output 0 while [ output <= highest ] [ ; find the maximum probability for outcome i across all states let maxProbForOutcome ( max ( n-values ( array:length ( [propensities] of s ) ) [ pair-probability s r ? output ] ) ) ; if the maximum probability is high enough, then this agent produces this outcome 'efficiently' if ( ( 100 * maxProbForOutcome ) > efficiency-threshold ) [ set efficientOutcomes ( efficientOutcomes + 1 ) ] ; increment outcome set output ( output + 1 ) ] ] report efficientOutcomes >= target end ; *************************************** ; DETERMINE WHETHER AN AGENT IS EFFICIENT ; *************************************** ; a single agent is 'efficient' just in case for every outcome that it can produce, there is ; an input that 'deterministically' (up to efficiency-threshold) produces it ; note that an agent could be doing 'as best it can' and NOT be rated 'efficient' by this ; algorithm; nonetheless, it could be useful in a context where agents are permitted to ; pair up with multiple agents of different sorts. ; ; note that agent can (of course) be a sender or a receiver to-report isEfficient [ agent ] let efficientOutcomes 0 ask agent [ ; an index to outcomes let i 0 ; the highest number of outcomes that this agent can produce for any input let maxOutput maxOutputs self ; as long as we are still potentially efficient, loop through possible outcomes while [ i < maxOutput ] [ ; find the maximum probability for outcome i across all inputs to (rows of) this agent's propensities ; obviously it is crucial that probForOutcome return zero when the outcome is higher than (or equal to) the length of the propensity let maxProbForI ( max ( n-values ( array:length propensities ) [ probForOutcome self i ? ] ) ) ; if the maximum probability is high enough, then this agent produces this outcome 'efficiently' if ( ( 100 * maxProbForI ) > efficiency-threshold ) [ set efficientOutcomes ( efficientOutcomes + 1 ) ] ; increment outcome set i ( i + 1 ) ] ] ; do not use maxInputs agent because that would defeat the purpose of this being a measure that is ; independent of the sender; if you are interested in the efficiency of the pair, use isPairEfficient! report efficientOutcomes = min ( list ( array:length [propensities] of agent ) ( maxOutputs agent ) ) end ; ****************************************************** ; DETERMINE THE LEVEL OF EFFICIENCY FOR A PAIR OF AGENTS ; ****************************************************** ; like isPairEfficient, but we report the percentage of outcomes that are efficiently produced ; because of how this number is used elsewhere, we leave it as a number between 0 and 1 to-report pairEfficiency [ s r ] ; how many outcomes SHOULD we be able to distinguish? let target ( max-outputs-for-pair r ) ; a count of efficiently produced outcomes let efficientOutcomes 0 ask r [ ; the highest numbered outcome we can even in principle produce let highest ( ( array:length ( array:item propensities 0 ) ) - 1 ) let output 0 while [ output <= highest ] [ ; find the maximum probability for outcome i across all states let maxProbForOutcome ( max ( n-values ( array:length ( [propensities] of s ) ) [ pair-probability s r ? output ] ) ) ; if the maximum probability is high enough, then this agent produces this outcome 'efficiently' if ( ( 100 * maxProbForOutcome ) > efficiency-threshold ) [ set efficientOutcomes ( efficientOutcomes + 1 ) ] ; increment outcome set output ( output + 1 ) ] ] report ( efficientOutcomes / target ) end ; **************************************************************** ; CALL THE APPROPRIATE MEASURE OF EFFICIENCY AND RETURN THE RESULT ; **************************************************************** ; to-report getEfficiency [ s r ] let eff 0 ifelse ( useAbsoluteEfficiency ) [ ; return 1 on efficient, 0 otherwise if ( isPairEfficient s r ) [ set eff 1 ] ] [ set eff ( pairEfficiency s r ) ] report eff end ; ********************************************* ; GRAB THE SENDER AND RECEIVER FROM A COMM-LINK ; ********************************************* ; returns sender as item 0, receiver as item 1 ; we are sensitive to the fact that there can be multiple ; links connecting senders and receivers, and that one agent ; can be both a sender and a receiver (and even linked to ; itself as such) ; ; we expect c to be a comm-link AND WE DON'T CHECK THAT IT IS! to-report getSenderAndReceiver [ c ] let s nobody let r nobody ask c [ let ags both-ends ; need to be careful here since we want to allow agents to be senders and receivers... ask ags [ ; need to proceed carefully here in case one or both is both sender and receiver if ( is-sender? self ) [ if ( not ( is-sender? s ) ) [ set s self ] ] if ( is-receiver? self ) [ if ( not (is-receiver? r ) ) [ set r self ] ] ] ; now we have to check that the link goes in the right direction, and if not, reverse it if ( not ( ( [out-comm-to r] of s ) = self ) ) [ ; we got it backwards! let temp nobody set temp s set s r set r temp ] ] report ( list s r ) end ; ************************** ; MONITOR OVERALL EFFICIENCY ; ************************** ; we presume c to be a set of comms (which link senders and receivers) to monitor-efficiency [ c ] ; the total number of efficient pairs let eff 0 ; ask each pair: what is your efficiency? ask c [ ; grab the sender and receiver from the comm-link (item 0 is sender; item 1 is receiver) let pairList getSenderAndReceiver self if ( ( (item 0 pairList) != nobody ) and ( (item 1 pairList) != nobody ) ) [ set eff ( eff + ( getEfficiency (item 0 pairList) (item 1 pairList) ) ) ] ] ; determine total efficiency set efficiency ( 100 * ( eff / ( count c ) ) ) ; are we tracking conv time avg? if ( efficiency-turning-point > 0 ) [ ; keep track of time-averaged convergence once we pass the turning-point ifelse ( efficiency > efficiency-turning-point ) [ ; are we already counting? ifelse ( ( first eff-list ) > 0 ) [ ; we are counting ; add the convergence for this period to the list set eff-list ( lput efficiency eff-list ) ; does that complete an interval of periods? (if not then we're done) if ( ( length eff-list ) >= time-avg-periods ) [ ; interval complete -- have we already added an element to the list of time averages? ifelse ( ( first eff-avgs-list ) > 0 ) [ ; yes, so just add this one set eff-avgs-list ( lput ( mean eff-list ) eff-avgs-list ) ] [ ; no, so this is the first one set eff-avgs-list ( list ( mean eff-list ) ) ] ; reset to begin counting again set eff-list ( list 0 ) ; does our list of time-averages exceed the allowed maximum size? if so, cut it down if ( ( length eff-avgs-list ) > time-avg-intervals ) [ set eff-avgs-list ( but-first eff-avgs-list ) ] ; Does the current list of time averages satisfy the halting conditions? ifelse ( eff-time-avg-halt and ( ( ( length eff-avgs-list ) >= time-avg-intervals ) and ( ( standard-deviation eff-avgs-list ) < efficiency-stability-threshold ) ) ) [ set eff-stop true ] [ ; when multiple criteria are in play for stopping, the efficiency criterion could get met, then 'unmet'. ; We choose to turn stopping off in this case and require the condition to be met again. set eff-stop false ] ] ] [ ; we are beginning a new interval of time-averaged periods ; record percentConv as the first value in the new interval set eff-list ( list efficiency ) ] ] [ ; this block is necessary in case we go above the turning-point then dip back down, in which case we reset everything set eff-list ( list 0 ) set eff-avgs-list (list 0 ) ] ] ; update plots if ( showPlots ) [ ; set-current-plot "Efficiency" ; set-current-plot-pen "default" set-current-plot "Accuracy (green), Efficiency (black), Convergence [stability] (red)" set-current-plot-pen "efficiency" plot efficiency ] end to-report allConverged if ( all? turtles [ isConverged self ] ) [ report true ] report false end ; ********************************* ; REMEMBER OUR CURRENT PROPENSITIES ; ********************************* to mark-propensities ask ( turtle-set senders receivers ) [ set markPropensities ( copy-propensities propensities ) set has-marked true ] end ; ************************ ; DISPOSITION COPY UTILITY ; ************************ to-report copy-propensities [ p1 ] let p2 flatPropensities ( array:length p1 ) ( array:length ( array:item p1 0 ) ) 0 let i 0 while [ i < array:length p1 ] [ let j 0 let thisRow array:item p1 i while [ j < array:length thisRow ] [ array:set (array:item p2 i) j ( array:item thisRow j ) set j ( j + 1 ) ] set i ( i + 1 ) ] report p2 end ; ************************** ; DETERMINE SOME FINAL STATS ; ************************** to final-stats ; force the (currently!) 'final' stats to be generated ; this is a dummy variable to allow us to run the commands (we don't need their output) let dummy 0 if ( ( monitorConv ) or ( convergence-halt-threshold < 100 ) ) [ set dummy monitor-convergence turtles ] if ( ( monitorKLDistance ) or ( kl-halt-threshold > 0 ) ) [ set dummy monitor-kl turtles ] if ( ( monitorAccuracy ) or ( accuracy-halt-threshold < 100 ) ) [ set dummy monitor-accuracy receivers ] if ( monitorEfficiency ) [ monitor-efficiency comms ] output-print " " let convList convergenceStats output-print word "Ticks: " ticks output-print word "Mean first Convergence Time: " ( round item 1 convList ) output-print word "STDV of first Convergence Times: " ( round item 2 convList ) output-print word "Mean last Convergence Time: " ( round item 3 convList ) output-print word "Mean Dist from Determinism: " ( round-to ( item 7 convList ) 4 ) output-print word "STDV of last Convergence Times: " ( round item 4 convList ) output-print word "Mean Accuracy: " ( round-to ( item 5 convList ) 2 ) output-print word "Mean Accuracy of Converged: " ( round-to ( item 6 convList ) 2 ) output-print word "Percent Efficient: " efficiency output-print word "Mean of last " ( word time-avg-intervals (word " Avg Efficiency: " ( round-to ( mean eff-avgs-list ) 2 ) ) ) if ( ( length eff-avgs-list ) > 1 ) [ output-print word "StdDev of last " ( word time-avg-intervals (word " Avg Efficiency: " ( round-to ( standard-deviation eff-avgs-list ) 2 ) ) ) ] output-print word "Percent Converged: " ( round-to ( item 0 convList ) 2 ) output-print word "Mean of last " ( word time-avg-intervals (word " Avg Convergence: " ( round-to ( mean conv-time-avgs-list ) 2 ) ) ) if ( ( length conv-time-avgs-list ) > 1 ) [ output-print word "StdDev of last " ( word time-avg-intervals (word " Avg Conv: " ( round-to ( standard-deviation conv-time-avgs-list ) 2 ) ) ) ] output-print "---------------------------------------" output-print " " end ; **************************************************** ; DETERMINE TOTAL PROPENSITY OF A ROW IN A DISPOSITION ; **************************************************** ; NB: We presume that propensity actually has the indicated row -- a run-time error will occur if it does not to-report totalPropensity [ prop row ] let tot 0 ; let i 0 ; let arr ( array:item prop row ) ; while [ i < array:length arr ] [ ; set tot ( tot + ( array:item arr i ) ) ; set i ( i + 1 ) ; ] ; testing new syntax... this should be faster than the above equivalent code foreach array:to-list ( array:item prop row ) [ set tot tot + ? ] report tot end ; ************************ ; SELECT FROM PROPENSITIES ; ************************ to-report selectFromPropensities [ p pstr input ] ; if total propensity is zero then the agent does nothing if ( pstr = 0 ) [ report -1 ] ; grab the agent's propensities corresponding to the input (state or signal) that the agent received let prop array:item p input ; determine the total strength ; generate a random number between 1 and pstr let target ( random (pstr - 1) ) + 1 ; index to walk through the propensities let i 0 ; sum of the items in the propensities let s 0 ; walk through the propensities, summing them as we go; once we get larger than target, we have our output. while [ i < array:length prop ] [ set s ( s + array:item prop i ) if ( s >= target ) [ report i ] set i (i + 1) ] ; We shouldn't ever get here -- if we do, then pstr was sent to this routine with an incorrect value output-type "WARNING: pstr = " output-type pstr output-print " was incorrectly sent to selectFromPropensities for propensities of " show-raw-propensities p output-print word "Input was " input output-print " -- Output is invalid -- " report ( i - 1 ) end ; ************************ ; RETURN FLAT PROPENSITIES ; ************************ to-report flatPropensities [inputs outputs propValue] ; return an NxM array of propensities of size propValue ; the first index is the 'input' (stimulus) and the second index is the 'output' (action) report array:from-list n-values inputs [ array:from-list n-values outputs [propValue] ] end ; ****************** ; SCALE PROPENSITIES ; ****************** to scalePropensities [ agent factor ] ask agent [ let i 0 while [ i < array:length propensities ] [ let j 0 while [ j < array:length ( array:item propensities i ) ] [ array:set ( array:item propensities i ) j ( round ( ( array:item ( array:item propensities i ) j ) * factor ) ) set j ( j + 1 ) ] set i ( i + 1 ) ] ] end ; ************************ ; PAD A STRING TO A LENGTH ; ************************ to-report padTo [ instr len ] let i 0 let str word instr " " while [ ( ( length str ) + i ) < len ] [ set str word str " " ] report str end ; ***************** ; SHOW PROPENSITIES ; ***************** to show-raw-propensities [ p ] let i 0 ; loop through the propensities while [ i < array:length p ] [ let arr array:item p i let str " " let j 0 ; loop through the propensity and turn it into a string while [ j < array:length arr ] [ set str word str ( padTo ( array:item arr j ) 16 ) set j ( j + 1 ) ] output-print str set i ( i + 1 ) ] end ; ******************************** ; SHOW PROPENSITIES AS PERCENTAGES ; ******************************** to show-propensities [ p ] let i 0 ; loop through the propensities while [ i < array:length p ] [ let arr array:item p i let tp ( totalPropensity p i ) let str " " let j 0 ; loop through the propensity and turn it into a string while [ j < array:length arr ] [ let pr round ( 100 * ( ( array:item arr j ) / ( tp ) ) ) set str ( word str pr ) ; add an appropriate amount of space ifelse ( pr < 10 ) [ set str word str " " ] [ ifelse ( pr < 100 ) [ set str word str " " ] [ set str word str " " ] ] set j ( j + 1 ) ] output-print str set i ( i + 1 ) ] end ; ***************************** ; SHOW ALL AGENTS' DISPOSITIONS ; ***************************** to showDisp output-print " DISPOSITIONS:" foreach sort receivers [ ask ? [ ask mySender [ output-print word "Sender " who show-propensities propensities if ( isConverged self ) [ output-print "CONVERGED" ] output-print " " ] output-print word "Receiver " who show-propensities propensities if ( isConverged self ) [ output-print "CONVERGED" ] output-print "-----------------------" ] ] end ; ***************************************** ; SHOW ALL UNCONVERGED AGENTS' DISPOSITIONS ; ***************************************** to show-unconverged output-print " UNCONVERGED DISPOSITIONS:" foreach sort receivers [ ask ? [ if ( ( not isConverged mySender ) or ( not isConverged self ) ) [ ask mySender [ output-print word "Sender " who show-propensities propensities output-print " " ] output-print word "Receiver " who show-propensities propensities output-print "-----------------------" ] ] ] end ; ***************************************** ; SHOW ALL INEFFICIENT AGENTS' DISPOSITIONS ; ***************************************** to show-inefficient output-print "INEFFICIENT:" foreach sort comms [ ask ? [ ; get the sender and receiver let pairList getSenderAndReceiver self if ( ( (item 0 pairList) != nobody ) and ( (item 1 pairList) != nobody ) ) [ if ( not ( isPairEfficient (item 0 pairList) (item 1 pairList) ) ) [ ask (item 0 pairList) [ output-print word "Sender " who show-propensities propensities output-print " " ] ask (item 1 pairList) [ output-print word "Receiver " who show-propensities propensities output-print " " ] output-print "-----------------------" ] ] ] ] end ; ****************************************************** ; DETERMINE AN AGENT'S PROBABILTY TO OUTPUT out GIVEN in ; ****************************************************** ; NB: we presume (for now) that an unrecognizeable input leads to no action (i.e., -1) so prob is zero. ; Likewise, an unperformable output always has prob = 0. to-report probForOutcome [ ag out in ] let prob 0 ask ag [ ; check that we can receive this input if ( in >= array:length propensities ) [ stop ] ; check that we can perform this output if ( out >= array:length (array:item propensities in) ) [ stop ] ; if we get here, then the output is performable on this input ; get the relevant row of the propensities let inRow ( array:item propensities in ) ; calculate the relevant prob set prob 0 let tp ( totalPropensity propensities in ) if ( tp > 0 ) [ set prob ( ( array:item inRow out ) / tp ) ] ] report prob end ; ***************************************** ; DETERMINE A MEASURE OF SUCCESS FOR A PAIR ; ***************************************** ; Report the average probability of a 'correct' prediction of a pair (represented by its receiver) ; where 'correct' means that they predict the drifted state, regardless of stdv. ; NOTE: Obviously we are not determining the actual rate of success, which depends on the stdv in the laws. ; We are determining the probability that they will make the best prediction that they can, which we refer to ; below as 'success'. ; NOTE ALSO: strictly speaking, when we determine the probability of success for a given world-state, we should ; weight by the probability that they will encounter that state; it is possible for world-states to have overall ; different rates of occurrence for certain combinations of laws and initial conditions. (Simple example: 4 world-states; ; drift = 2; stdv = 0; initial state = 1. The world will just evolve as 1-3-1-3-1-3...) However, we are going to ; assume, here, that the drift is not too pathological, that the stdv is large enough, and the time-horizon long ; enough, the all states occur with roughly equal probability. ; We could easily enough keep track of how many times each state occurs to determine an actual chance of success ; 'in this world as it actually unfolded', and that number could potentially be of interest. Maybe later... to-report pairAccuracy [ rcv ] ; this variable holds the sum of probabilities of success let probSum 0 ; the receiver does the calculation ask rcv [ ; loop through all world states let i 0 while [ i < states ] [ ; determine the 'correct' prediction let correct round ( ( i + laws-drift ) mod states ) ; determine the probability that the pair will predict 'correct' on input i ; this probability is (see NOTE ALSO above!): ; ; SUM_signal Pr_sender(signal | i) * Pr_receiver(correct | signal) ; let totalProb 0 let j 0 ; in case the receiver has fewer 'inputs' than the sender has signals, we need to sum just ; over the signals that receiver can detect -- probability of success is zero when other signals are ; sent as receiver won't act at all! (See turtles-act for further thoughts on this situation.) let rec-inputs array:length propensities while [ j < rec-inputs ] [ ; prob that we will send this signal times prob of success if we send this signal, summed into totalProb set totalProb ( totalProb + ( (probForOutcome mySender j i) * (probForOutcome self correct j) ) ) set j ( j + 1 ) ] ; So prob of success for this world-state is totalProb, which we then add to probSum set probSum ( probSum + totalProb ) ; increment state set i ( i + 1 ) ] ] ; So now probSum contains the SUM of probabilities of success on each possible world-state. ; Report the average (i.e., we are weighting all world-states equally -- see above) report probSum / states end ; *************************************************************************** ; RETURN THE PROB THAT A PAIR GIVES TO AN OUTPUT (ACT) ON GIVEN INPUT (STATE) ; *************************************************************************** to-report pair-probability [ s r input output ] let rec-inputs array:length ( [propensities] of r ) let j 0 let totalProb 0 while [ j < rec-inputs ] [ ; prob that s will send signal j given input, times prob of output given signal j, summed into totalProb set totalProb ( totalProb + ( ( probForOutcome s j input ) * ( probForOutcome r output j ) ) ) set j ( j + 1 ) ] report totalProb end ; ************************************************************************ ; RETURN A MEASURE OF HOW MUCH AN AGENT HAS CHANGED FROM ITS PREVIOUS SELF ; ************************************************************************ to-report mean-kl-divergence-from-previous [ a ] let r 0 ask a [ set r mean-kl-divergence ( propensityArray2disposition propensities) ( propensityArray2disposition markPropensities ) ] report r end ; ********************************************************** ; RETURN THE MEAN CHANGE (KL-DIVERGENCE) FOR A SET OF AGENTS ; ********************************************************** ; Note: limit the set of agents when invoking this function to get the desired output to-report mean-mean-kl-divergence-from-previous [ ag ] let r -1 let total 0 ask ag [ set total ( total + ( mean-kl-divergence-from-previous self ) ) ] ifelse ( count ag > 0 ) [ set r ( total / ( count ag ) ) ] [ output-print "WARNING: apparently no agents were used to calculate mean-mean-kl-divergence from previous. Reporting -1." ] report r end ; *************************************************** ; RETURN A MEASURE OF HOW MUCH AN AGENT HAS CONVERGED ; *************************************************** to-report mean-kl-divergence-from-determinism [ p ] let i 0 let tot 0 while [ i < array:length p ] [ set tot ( tot + ( kl-divergence ( nearest-deterministic-distribution ( array:item p i ) ) ( propensities2distribution ( array:item p i ) ) ) ) set i ( i + 1 ) ] report tot / i end ; ************************************************** ; RETURN THE KL-DIVERGENCE BETWEEN TWO DISTRIBUTIONS ; ************************************************** to-report kl-divergence [ d1 d2 ] let kld 0 let i 0 while [ i < array:length d1 ] [ if ( ( array:item d1 i ) > 0 ) [ ; FIXME: Is this the best way to handle the problem that the numbers can get too darned big? And when they are zero? carefully [ ; effectively, we turn zeros into 10^-4. let d 10 ^ -4 if ( array:item d2 i != 0 ) [ set d array:item d2 i ] set kld ( kld + ( ( array:item d1 i ) * (log ( ( array:item d1 i ) / ( d ) ) 2 ) ) ) ] [ output-print error-message output-print word "Division by " ( array:item d2 i ) ] ] set i ( i + 1 ) ] report kld end ; ****************************************************** ; RETURN THE MEAN KL-DIVERGENCE BETWEEN TWO DISPOSITIONS ; ****************************************************** to-report mean-kl-divergence [ d1 d2 ] let tkld 0 let i 0 while [ i < array:length d1 ] [ set tkld ( tkld + ( kl-divergence ( array:item d1 i ) ( array:item d2 i ) ) ) set i ( i + 1 ) ] report tkld / ( array:length d1 ) end ; ******************************************************************* ; RETURN PROPENSITIES THAT ARE DETERMINISTIC AND CLOSEST TO THE INPUT ; ******************************************************************* to-report nearest-deterministic-distribution [ p ] ; find the highest propensity let currentMax 0 let maxPropIndex 0 let i 0 ; which item in the propensities is highest? while [ i < array:length p ] [ if ( ( array:item p i ) > currentMax ) [ set currentMax ( array:item p i ) set maxPropIndex i ] set i ( i + 1 ) ] ; make an array of zeros let ret array:from-list n-values ( array:length p ) [ 0 ] ; set the array item at the index that we found above to 1 array:set ret maxPropIndex 1 report ret end ; ************************************************************ ; RETURN AN ARRAY OF DISTRIBUTIONS BASED ON A PROPENSITY ARRAY ; ************************************************************ to-report propensities2distribution [ p ] ; initialize a flat distribution with all zeros let ret array:from-list n-values ( array:length p ) [ 0 ] ; get the total let i 0 let tp 0 while [ i < array:length p ] [ set tp ( tp + ( array:item p i ) ) set i ( i + 1 ) ] set i 0 ; loop through the propensities while [ i < array:length p ] [ let pr 0 if ( tp > 0 ) [ set pr ( ( array:item p i ) / tp ) ] ; record the probability array:set ret i pr set i ( i + 1 ) ] report ret end ; **************************************************************** ; RETURN A FULL DISPOSITION BASED ON AN ARRAY OF PROPENSITY ARRAYS ; **************************************************************** to-report propensityArray2disposition [ p ] ; piggyback on flatPropensities to get started let d flatPropensities ( array:length p ) ( array:length (array:item p 0) ) 0 ; reset each row using propensities2distribution let i 0 while [ i < array:length p ] [ array:set d i ( propensities2distribution ( array:item p i ) ) set i ( i + 1 ) ] report d end ; *********************************************** ; GET ALL CONVERGENCE TIMES FROM A SET OF TURTLES ; *********************************************** to-report collectConvergenceStats [ t useFirst ] let cs array:from-list n-values ( count t ) [ 0 ] ask t [ ifelse ( useFirst ) [ array:set cs who firstConverged ] [ array:set cs who lastConverged ] ] report cs end ; ********************************** ; ROUND A NUMBER TO d DECIMAL PLACES ; ********************************** to-report round-to [ n d ] let big n * ( 10 ^ d ) set big round big report big / ( 10 ^ d ) end ; ************************************************** ; DETERMINE VARIOUS STATISTICS REGARDING CONVERGENCE ; ************************************************** to-report convergenceStats ; iterate through convergence-times and count how many are converged, how long it took, and other things ; Returns a list: ; item 0: Percent converged ; item 1: Mean first convergence time ; item 2: Standard deviation of first convergence times ; item 3: Mean last convergence time ; item 4: Standard deviation of last convergence times ; item 5: Mean accuracy ; item 6: Mean accuracy among those that are (or were) converged ; item 7: Mean mean KL-distance from determinism ; ; Note that none of these stats cares what method we use to determine whether an agent is 'converged'. let i 0 let fconv 0 let totalfconvtime 0 let actualfConvTimes ( list 0 ) let fconvergence-times collectConvergenceStats turtles true while [ i < array:length fconvergence-times ] [ if ( ( array:item fconvergence-times i ) > -1 ) [ set fconv ( fconv + 1 ) set totalfconvtime ( totalfconvtime + ( array:item fconvergence-times i ) ) set actualfConvTimes ( fput ( array:item fconvergence-times i ) actualfConvTimes ) ] set i ( i + 1 ) ] let stdfConv -1 let avgfConv -1 if ( fconv > 1 ) [ set stdfConv ( standard-deviation ( but-last actualfConvTimes ) ) set avgfConv round ( totalfconvtime / fconv ) ] ; This is inelegant -- basically just repeating the code above for last convergence times ; I can't be bothered to make a separate function right now... set i 0 let lconv 0 let totallconvtime 0 let actuallConvTimes ( list 0 ) let lconvergence-times collectConvergenceStats turtles false while [ i < array:length lconvergence-times ] [ if ( ( array:item lconvergence-times i ) > -1 ) [ set lconv ( lconv + 1 ) set totallconvtime ( totallconvtime + ( array:item lconvergence-times i ) ) set actuallConvTimes ( fput ( array:item lconvergence-times i ) actuallConvTimes ) ] set i ( i + 1 ) ] let stdlConv -1 let avglConv -1 if ( lconv > 1 ) [ set stdlConv ( standard-deviation ( but-last actuallConvTimes ) ) set avglConv round ( totallconvtime / lconv ) ] let pc ( 100 * ( lconv / ( array:length lconvergence-times ) ) ) ; determine the average accuracy of all pairs and all converged pairs let accuracySum 0 let convAccuracySum 0 let convPairs 0 ask receivers [ let acc ( pairAccuracy self ) set accuracySum ( accuracySum + acc ) if ( converged and ( [ converged ] of mySender ) ) [ set convAccuracySum ( convAccuracySum + acc ) set convPairs ( convPairs + 1 ) ] ] let avgAccuracy ( 100 * ( accuracySum / ( count receivers ) ) ) let avgConvAccuracy -1 if ( convPairs > 0 ) [ set avgConvAccuracy ( 100 * ( convAccuracySum / convPairs ) ) ] ; determine mean kl divergence from determinism let meanKL 0 let mmkl 0 let mmkl-count 0 ; determine mean kl-divergece amongst all agents ; and record what needs recording for the agent ask turtles [ let kls mean-kl-divergence-from-determinism propensities set mmkl ( mmkl + kls ) set mmkl-count ( mmkl-count + 1 ) ] set meanKL ( mmkl / mmkl-count ) report ( list pc avgfConv stdfConv avglConv stdlConv avgAccuracy avgConvAccuracy meanKL ) end to output-notes output-print notes end @#$#@#$#@ GRAPHICS-WINDOW 725 25 1010 147 1 0 91.7 1 10 1 1 1 0 1 1 1 -1 1 0 0 0 0 1 ticks 30.0 SLIDER 198 126 345 159 acts acts 2 32 8 1 1 NIL HORIZONTAL SLIDER 197 56 345 89 states states 2 32 8 1 1 NIL HORIZONTAL SLIDER 197 91 345 124 signals signals 2 32 8 1 1 NIL HORIZONTAL SLIDER 198 267 346 300 laws-stdv laws-stdv 0 100 0.5 .05 1 NIL HORIZONTAL SLIDER 198 302 346 335 laws-drift laws-drift 0 32 3.25 .25 1 NIL HORIZONTAL SLIDER 167 579 351 612 state-perception-stdv state-perception-stdv 0 16 0 .05 1 NIL HORIZONTAL SLIDER 167 647 351 680 sender-experimentation sender-experimentation 0 16 0.25 .05 1 NIL HORIZONTAL INPUTBOX 5 210 189 270 timeout 100000 1 0 Number SLIDER 197 439 344 472 payoff payoff 1 100 5 1 1 NIL HORIZONTAL SLIDER 197 371 345 404 propensity-init propensity-init 5 500 100 5 1 NIL HORIZONTAL SLIDER 197 232 345 265 pairs pairs 1 10000 40 1 1 NIL HORIZONTAL BUTTON 4 10 60 43 Setup clear-output\nsetup NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 65 10 120 43 Go go T 1 T OBSERVER NIL NIL NIL NIL 1 SLIDER 5 105 189 138 max-prob-threshold max-prob-threshold 0 100 100 1 1 NIL HORIZONTAL SLIDER 5 272 189 305 convergence-resolution convergence-resolution 0 1000 100 5 1 NIL HORIZONTAL BUTTON 1376 10 1459 43 Show Disp showDisp NIL 1 T OBSERVER NIL NIL NIL NIL 1 PLOT 358 49 1363 480 Accuracy (green), Efficiency (black), Convergence [stability] (red) Periods Percentage 0.0 200.0 0.0 100.0 true false "" "" PENS "default" 1.0 0 -16777216 true "" "" "percentConv" 1.0 0 -16777216 true "" "" "accuracy" 1.0 0 -10899396 true "" "" "efficiency" 1.0 0 -16777216 true "" "" "convergence" 1.0 0 -2674135 true "" "" SWITCH 7 714 157 747 showPlots showPlots 0 1 -1000 SLIDER 198 509 344 542 forgetfulness forgetfulness .9 1 0.96 .001 1 NIL HORIZONTAL SLIDER 167 613 351 646 signal-perception-stdv signal-perception-stdv 0 16 0 .05 1 NIL HORIZONTAL SLIDER 167 682 352 715 receiver-experimentation receiver-experimentation 0 16 0.25 .05 1 NIL HORIZONTAL OUTPUT 1378 56 1903 880 12 PLOT 980 487 1367 881 Mean-Mean-KL Divergence from Determinism Periods Mean Mean KL 0.0 200.0 0.0 1.0 true false "" "" PENS "default" 1.0 0 -16777216 true "" "" "meanKL" 1.0 0 -16777216 true "" "" "meanKLInactive" 1.0 0 -7500403 true "" "" SWITCH 7 549 157 582 monitorKLDistance monitorKLDistance 0 1 -1000 SLIDER 198 544 345 577 forget-interval forget-interval 0 500 100 1 1 NIL HORIZONTAL SLIDER 197 405 344 438 minimum-propensity minimum-propensity 0 1000 1 1 1 NIL HORIZONTAL SLIDER 197 474 345 507 penalty penalty 0 100 1 1 1 NIL HORIZONTAL BUTTON 258 10 340 43 Final Stats final-stats NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 1723 10 1786 43 Save let myfile user-new-file\nif ( is-string? myfile ) [\n export-output myfile\n] NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 1788 10 1852 43 Clear clear-output NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 1544 10 1643 43 Show Unconv show-unconverged NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 123 10 178 43 Mark mark-propensities NIL 1 T OBSERVER NIL NIL NIL NIL 1 CHOOSER 5 57 189 102 convergenceMethod convergenceMethod "Maximum Probability" "KL Divergence" 1 SLIDER 5 140 189 173 kl-div-threshold kl-div-threshold 0 .1 0.0025 .00001 1 NIL HORIZONTAL SLIDER 197 197 344 230 receiver-inputs receiver-inputs 2 32 8 1 1 NIL HORIZONTAL SLIDER 198 161 345 194 sender-inputs sender-inputs 2 32 8 1 1 NIL HORIZONTAL INPUTBOX 7 757 353 879 notes 8x8relearn_exp 1 1 String SLIDER 5 343 190 376 convergence-halt-threshold convergence-halt-threshold 0 100 100 1 1 NIL HORIZONTAL SLIDER 5 308 190 341 kl-halt-threshold kl-halt-threshold 0 .0001 0 .000001 1 NIL HORIZONTAL SLIDER 5 411 189 444 halt-periods halt-periods 0 25 10 1 1 NIL HORIZONTAL SLIDER 5 377 189 410 accuracy-halt-threshold accuracy-halt-threshold 0 100 100 1 1 NIL HORIZONTAL SLIDER 5 174 189 207 kl-div-threshold-periods kl-div-threshold-periods 1 100 10 1 1 NIL HORIZONTAL SWITCH 7 582 157 615 monitorConv monitorConv 0 1 -1000 SWITCH 7 614 157 647 monitorAccuracy monitorAccuracy 0 1 -1000 SWITCH 7 647 157 680 monitorEfficiency monitorEfficiency 0 1 -1000 SLIDER 5 445 189 478 efficiency-threshold efficiency-threshold 0 100 85 1 1 NIL HORIZONTAL BUTTON 1644 10 1722 43 Print Notes output-notes NIL 1 T OBSERVER NIL NIL NIL NIL 1 BUTTON 1299 10 1362 43 test ;set-agent-propensities turtle 0\n;show kl-change turtle 0 NIL 1 T OBSERVER NIL NIL NIL NIL 1 SLIDER 198 336 346 369 laws-surprise laws-surprise 0 1 0.01 .01 1 NIL HORIZONTAL SLIDER 354 487 556 520 convergence-turning-point convergence-turning-point 0 100 0 1 1 NIL HORIZONTAL SLIDER 354 524 557 557 efficiency-turning-point efficiency-turning-point 0 100 77 1 1 NIL HORIZONTAL SLIDER 354 559 557 592 time-avg-periods time-avg-periods 0 100 10 1 1 NIL HORIZONTAL SLIDER 559 524 756 557 convergence-stability-threshold convergence-stability-threshold 0 10 0.25 .05 1 NIL HORIZONTAL SWITCH 559 488 755 521 conv-time-avg-halt conv-time-avg-halt 1 1 -1000 SLIDER 355 595 557 628 time-avg-intervals time-avg-intervals 0 100 5 1 1 NIL HORIZONTAL SWITCH 560 561 755 594 eff-time-avg-halt eff-time-avg-halt 1 1 -1000 SLIDER 560 595 754 628 efficiency-stability-threshold efficiency-stability-threshold 0 10 0.25 .05 1 NIL HORIZONTAL MONITOR 760 489 889 534 Std Dev of Conv Times standard-deviation conv-time-avgs-list 5 1 11 MONITOR 761 537 888 582 Std Dev of Efficiencies standard-deviation eff-avgs-list 5 1 11 INPUTBOX 355 632 979 879 parameters set param-list ( list\n \"/Users/michael/Documents/research/sender-receiver-games/results/SIGNAL_10000_SD/plot\"\n ( list \"states\" 4 4 4 4 4 4 4 4 4 4 )\n ( list \"signals\" 4 4 4 4 4 4 4 4 4 4 )\n ( list \"acts\" 4 4 4 4 4 4 4 4 4 4 )\n ( list \"sender-inputs\" 4 4 4 4 4 4 4 4 4 4 )\n ( list \"receiver-inputs\" 4 4 4 4 4 4 4 4 4 4 )\n ( list \"state-perception-stdv\" 0 0 0 0 0 0 0 0 0 0 )\n ( list \"signal-perception-stdv\" 0 0 0 0 0 0 0 0 0 0 )\n ( list \"sender-experimentation\" 0 0 0 0 0 0 0 0 0 0 )\n ( list \"receiver-experimentation\" 0 0 0 0 0 0 0 0 0 0 )\n \"/Users/michael/Documents/research/sender-receiver-games/results/SIGNAL_10000_SD/output\"\n ) 1 1 String BUTTON 181 10 255 43 Go Many go-many NIL 1 T OBSERVER NIL NIL NIL NIL 1 SWITCH 759 595 881 628 save-results save-results 1 1 -1000 BUTTON 1459 10 1544 43 Show Ineff show-inefficient NIL 1 T OBSERVER NIL NIL NIL NIL 1 SLIDER 6 483 189 516 catastrophe-freq catastrophe-freq 0 .001 0 .00001 1 NIL HORIZONTAL SLIDER 6 516 189 549 catastrophe-penalty catastrophe-penalty 0 100 0 1 1 NIL HORIZONTAL CHOOSER 358 10 509 55 game-type game-type "SIGNAL" "PREDICTION" 1 SWITCH 7 680 157 713 useAbsoluteEfficiency useAbsoluteEfficiency 1 1 -1000 BUTTON 899 546 976 580 Show Prob output-print word \"SENDER \" showturtle\nshow-propensities [propensities] of turtle showturtle\noutput-print word \"RECEIVER \" ( showturtle + 1 )\nshow-propensities [propensities] of turtle ( showturtle + 1 )\n NIL 1 T OBSERVER NIL NIL NIL NIL 1 INPUTBOX 896 487 977 547 showturtle 0 1 0 Number BUTTON 899 582 976 616 Show Raw output-print word \"SENDER \" showturtle\nshow-raw-propensities [propensities] of turtle showturtle\noutput-print word \"RECEIVER \" ( showturtle + 1 )\nshow-raw-propensities [propensities] of turtle ( showturtle + 1 )\n NIL 1 T OBSERVER NIL NIL NIL NIL 1 SLIDER 168 719 354 752 mark-ticks-max mark-ticks-max 0 10000 5000 100 1 NIL HORIZONTAL @#$#@#$#@ ## HOW TO USE IT ## BASIC OPERATION Setup: Once all parameters are set where you want, click the 'Setup' button. (Note, if you change certain parameters (such as pairs) after 'setup', you must click 'Setup' again or the simulation will be run with the old parameters. Clicking 'Setup' is NOT necessary if you are using 'Go Many', but IS NECESSARY if you are using 'Go'. Go: Run the simulation once. It will run until it halts on its own or you click 'Go' again. You can stop and restart as many times as you want. A stopped simulation can be continued simply by clicking 'Go' again (without clicking Setup, which would just start a new simulation). Mark: Clicking this button makes each agent remember its current disposition. ('Marking' is most safely done while the simulation is paused -- click it 'on the fly' and risk anomalous results!) This can be useful for comparison with their later selves. (A few functions are written to handle this comparison, but they must be invoked on the command line as there aren't buttons for them, yet, so they won't work in the web version anyway). Go Many: This is a way to run (and save the results of) many simulations for different values of the parameters. THe details are undocumented for now. THe configuration happens in the 'parameters' box. Feel free to play with it if you wish. (Minimal hint: the configuration there runs the same simulation 10 times and saves both the results and the output area to my hard drive.) If t the save-results switch is On then the results of each simulation are saved. Final Stats: Show a few stats about the simulation in its current state. (It doesn't really have to be 'final' -- you can click it any time). test: Used during code testing. Not useful when running simulations. Show Disp: Show all agent dispositions (shown as matrices of probabilities). Show Ineff: Show the dispositions of all pairs of inefficient agents (basically, anybody who is partially pooled) Show Unconv: Show the dispositions of all unconverged agents. Print Notes: Add any contents of the Notes window to the Output Window (useful for making notes on a run then saving) Save: Save the contents of the output window to a file. Clear: Clear the contents of the output window. ## WHAT IS HAPPENING AND WHAT ALL THE OPTIONS MEAN The simulation can run both 'signal' games and 'prediction' games. There is a pull-down menu ('game-type') to choose. In a signaling game you are responsible for setting the world dynamics appropriately. (If you want the usual random selection of the state at each round of the game, set laws-stdv and laws-drift to 0, and laws-surprise to 1.) Senders and receivers mate for life in this game. Agents: The simulation will run the game for pairs many sender-receiver pairs. They know nothing of one another. NetLogo is smart enough about randomness that there shouldn't be any illegitimate correlation in their evoluations, and there does not appear to be. Currently the maximum is set to 500 but this choice was arbitrary. Senders can have up to 32 signals. Receivers can have up to 32 acts. (There is no reason for this limitation apart from the fact that even at 32, things take a while.) In addition, you can set sender-inputs so that senders are 'sensitive' to fewer states than the world has. (In principle they could also be sensitive to more states than the world has, but this situation would have zero effect on the results of the simulation.) Similarly, receiver-inputs governs how many of sender's signals receiver can 'hear'. There are no constraints (other than being limited to 32) on these numbers. Any combination can be run. In addition, senders and receivers can be made to misperceive. A sender 'sees' a state of the world that is chosen from a normal distribution centered at the actual state of the world, with standard deviation state-perception-stdv. (Fine print: We choose a floating point number according to that distribution, then round to the nearest whole number, then mod it by the number of states that sender can actually see, i.e., sender-inputs.) Similarly, a receiver 'hears' a signal that is chosen from a normal distribution centered at the actual signal sent by sender, with standard deviation state-perception-stdv. (Same fine print, mutatis mutandis. And so on every time we choose something from a normal distribution.) Note that for this and similar purposes, the state space is a 'ring', i.e., the next state 'after' the maximum is 0. The same is true for the space of world-states, sender-inputs, signals, receiver-inputs, and acts. Finally, agents may 'experiment'. When a sender chooses a signal, actually it first chooses a 'provisional' signal. The actual signal is then chosen from a normal distribution centered at this provisional signal, with standard deviation sender-experimentation. Similarly, actual acts of the receiver are chosen according to receiver-experimentation. World: The states variable is the number of states of the world. It is initially chosen randomly (from a flat distribution). It then evolves as follows. First it is incremented by laws-drift, and then a state is chosen from a normal distribution centered at the drifted state, with standard deviation laws-stdv. However, with probability laws-surprise, this normal course of evolution is disrupted and the state is chosen randomly (from a flat distribution). Learning: When a pair succeeds, the corresponding propensities are increase by payoff. When they fail, the corresponding propensities are decreased by penalty, except that with probability catastrophe-freq, they are decreased by catastrophe-penalty. Each propensity begins with value propensity-init and is not allowed to be smaller than minimum-propensity. Every forget-interval rounds of the game, all propensities are multiplied by forgetfullness then rounded to the nearest whole number. Statistics: Statistics are gathered (and optionally plotted if showPlots is On) every convergence-resolution rounds of the game. Yes, this name is a poor choice. It should be called something like 'stat-period' and probably will be in some future revision of the code. Below, I refer to a number of rounds of the game equal to convergence-resolution as a 'period'. Convergence The 'convergence' of a single agent can be measured in one of two ways. The first (convergenceMethod = Maximum Probability) says that an agent is 'converged' if every row of its disposition has a probability greater than max-prob-threshold. This measure is crude and reports undesirable results in some circumstances, but it is fast. The second method (convergenceMethod = KL Divergence) measures the mean Kullback-Leibler divergence from the rows of the agent's disposition (represented as probabilities, not propensities) at the previous period to the corresponding rows at this period. (This is also the relative entropy. It is not a metric on probability distributions, but it is nonetheless a good 'measure' of how close two distributions are.) The 'mean' here refers to the mean of the KL-divergences of each of the rows. If that number is below kl-div-threshold for kl-div-threshold-periods many periods in a row. Agents can be converged at one time, and unconverged at a later time. Indeed, this situation frequently occurs. Note that in some scenarios, especially if state spaces are large, there can be some 'phantom' convergence early in the simulation. This phantom convergence is due to the fact that the total propensity in a row will generally start off quite high relative to EVERY entry in the row, so that a reward or penalty to a single entry will have very little overall effect on convergence. One could, I suppose, write code to ignore these phantom convergences, but as they invariably go away in the middle part of the simulation, they are hamrless. By the end, we are seeing geniune convergence, perhaps better termed 'long-term stability', in the dispositions. Accuracy Accuracy is the mean probability that a pair will make the best prediction possible. Note that when the state drifts (laws-drift > 0) the best prediction possible is the drifted state (rounded and mod states, of course), even if there is randomness in the evolution. (If there is no randomness in the evolution, then we are playing a deterministic version of the game, which is equivalent to the signaling game if (and only if) the drift is such that all states are visited with equal frequency. Efficiency Efficiency can mean one of two things. If useAbsoluteEfficiency is turned on, then a pair is efficient if they 'do their best' to associate world-states deterministically with sets of receiver-acts. In the 'straight' cases, where states = signals = acts = sender-inputs = receiver-inputs, this condition just means that their dispositions generate a one to one corredponence between world-states and acts. (There is no partial pooling.) In other cases, the meaning is slightly different. For example, if there is a 'bottleneck' somewhere in the system (e.g., signals < states) then we require this one to one correspondence only for the number of distinct states that COULD simultaneously, in the best of circumstances given the dimensions of their dispositions, be triggers for deterministically produced acts. Note also, for example, that this definition allows for mixed strategies to be played by the sender in cases where it has more signals than necessary. Finally, by 'deterministically' we really mean 'with probability greater than efficiency-threshold'. If useAbsoluteEfficiency is turned off, then efficiency refers to the number of outputs that the pair has associated 'deterministically' to an input, divided by the total number that they could simultaneously associate deterministically to an input. (Again, in straight cases, this number is just the number of states of the world.) Mean Mean KL-Divergence from Determinism The mean across all agents of their mean KL-Divergence from the nearest fully deterministic disposition. (The nearest fully deterministic disposition is the one in which each row has a 1 in the slot where the agent's disposition has its largest propensity (for that row), and 0s elsewhere.) Halting: Several conditions can be set to trigger the simulation to halt. When a simulation halts by meeting one of these conditions, it can be restarted, but will halt after one period unless the condition that caused the halt is changed. 1. If the number of rounds gets to the value in timeout, the simulation will halt. Set to zero to disable. 2. If the mean accuracy gets above accuracy-halt-threshold is exceeded for halt-periods many consecutive periods, the simulation will halt. Set to 100 to disable. 3. If more than convergence-halt-threshold percent of the agents have been converged for halt-periods many consecutive periods, the simulation will halt. Note: this does not have to be the SAME agents at each period. It just has to be true that the required percentage were converged at each period. 4. If the mean mean KL-Divergence from determinism is below kl-halt-threshold for halt-periods many consecutive periods, the simulation will halt. 5. Finally, we can make the simulation halt once the three statistics that we are measuring get 'flat enough'. As a matter of practice, accuracy flattens out and stays flat before the other two do, so we really just need to worry about them. Here's how it works. We are going to time-average their values, taking the mean value over time-avg-periods. So, for example, if convergence-resolution is set to 100 and time-avg-periods is set to 20, then a single time-averaged value is obtained by taking the mean of the 20 samples, taken one per 100-round period. Call the stretch of 'time' over which this single time-averaged value is calculated an 'interval'. We are going to collect time-avg-intervals of these time-averaged values, and then determine the standard deviation of the values. (Those standard deviations are shown in the two boxes below the main plot.) Note that once we collect the time-avg-intervals + 1st value, the oldest value is dropped from the list and we recalculate the standard deviation. If the standard deviation of the time-averaged convergences is below convergence-stability-threshold, then convergence halting condition is true. If the standard deviation of the time-averaged efficiencies is below efficiency-stability-threshold, then the efficiency halting condition is true. If conv-time-avg-halt is On then the convergence halting condition must be true for the simulation to halt. If eff-time-avg-halt is On then the efficiency halting conditoin must be true for the simulation to halt. If more than one of conditions 1-5 is enabled, they are combined disjunctively. (If any is met, the simulation halts.) Finally, the four buttons monitorKLDistance, monitorConv, monitorAccuracy, and monitorEfficiency are a little inconsistent in their behavior. They are really there for testing purposes and it is best to leave them all On when running a simulation if you care about the results. @#$#@#$#@ default true 0 Polygon -7500403 true true 150 5 40 250 150 205 260 250 airplane true 0 Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15 arrow true 0 Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150 box false 0 Polygon -7500403 true true 150 285 285 225 285 75 150 135 Polygon -7500403 true true 150 135 15 75 150 15 285 75 Polygon -7500403 true true 15 75 15 225 150 285 150 135 Line -16777216 false 150 285 150 135 Line -16777216 false 150 135 15 75 Line -16777216 false 150 135 285 75 bug true 0 Circle -7500403 true true 96 182 108 Circle -7500403 true true 110 127 80 Circle -7500403 true true 110 75 80 Line -7500403 true 150 100 80 30 Line -7500403 true 150 100 220 30 butterfly true 0 Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240 Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240 Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163 Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165 Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225 Circle -16777216 true false 135 90 30 Line -16777216 false 150 105 195 60 Line -16777216 false 150 105 105 60 car false 0 Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180 Circle -16777216 true false 180 180 90 Circle -16777216 true false 30 180 90 Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89 Circle -7500403 true true 47 195 58 Circle -7500403 true true 195 195 58 circle false 0 Circle -7500403 true true 0 0 300 circle 2 false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 cow false 0 Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167 Polygon -7500403 true true 73 210 86 251 62 249 48 208 Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123 cylinder false 0 Circle -7500403 true true 0 0 300 dot false 0 Circle -7500403 true true 90 90 120 face happy false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240 face neutral false 0 Circle -7500403 true true 8 7 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Rectangle -16777216 true false 60 195 240 225 face sad false 0 Circle -7500403 true true 8 8 285 Circle -16777216 true false 60 75 60 Circle -16777216 true false 180 75 60 Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183 fish false 0 Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166 Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165 Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60 Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166 Circle -16777216 true false 215 106 30 flag false 0 Rectangle -7500403 true true 60 15 75 300 Polygon -7500403 true true 90 150 270 90 90 30 Line -7500403 true 75 135 90 135 Line -7500403 true 75 45 90 45 flower false 0 Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135 Circle -7500403 true true 85 132 38 Circle -7500403 true true 130 147 38 Circle -7500403 true true 192 85 38 Circle -7500403 true true 85 40 38 Circle -7500403 true true 177 40 38 Circle -7500403 true true 177 132 38 Circle -7500403 true true 70 85 38 Circle -7500403 true true 130 25 38 Circle -7500403 true true 96 51 108 Circle -16777216 true false 113 68 74 Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218 Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240 house false 0 Rectangle -7500403 true true 45 120 255 285 Rectangle -16777216 true false 120 210 180 285 Polygon -7500403 true true 15 120 150 15 285 120 Line -16777216 false 30 120 270 120 leaf false 0 Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195 Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195 line true 0 Line -7500403 true 150 0 150 300 line half true 0 Line -7500403 true 150 0 150 150 pentagon false 0 Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120 person false 0 Circle -7500403 true true 110 5 80 Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90 Rectangle -7500403 true true 127 79 172 94 Polygon -7500403 true true 195 90 240 150 225 180 165 105 Polygon -7500403 true true 105 90 60 150 75 180 135 105 plant false 0 Rectangle -7500403 true true 135 90 165 300 Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285 Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285 Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210 Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135 Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135 Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60 Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90 sheep false 0 Rectangle -7500403 true true 151 225 180 285 Rectangle -7500403 true true 47 225 75 285 Rectangle -7500403 true true 15 75 210 225 Circle -7500403 true true 135 75 150 Circle -16777216 true false 165 76 116 square false 0 Rectangle -7500403 true true 30 30 270 270 square 2 false 0 Rectangle -7500403 true true 30 30 270 270 Rectangle -16777216 true false 60 60 240 240 star false 0 Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108 target false 0 Circle -7500403 true true 0 0 300 Circle -16777216 true false 30 30 240 Circle -7500403 true true 60 60 180 Circle -16777216 true false 90 90 120 Circle -7500403 true true 120 120 60 tree false 0 Circle -7500403 true true 118 3 94 Rectangle -6459832 true false 120 195 180 300 Circle -7500403 true true 65 21 108 Circle -7500403 true true 116 41 127 Circle -7500403 true true 45 90 120 Circle -7500403 true true 104 74 152 triangle false 0 Polygon -7500403 true true 150 30 15 255 285 255 triangle 2 false 0 Polygon -7500403 true true 150 30 15 255 285 255 Polygon -16777216 true false 151 99 225 223 75 224 truck false 0 Rectangle -7500403 true true 4 45 195 187 Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194 Rectangle -1 true false 195 60 195 105 Polygon -16777216 true false 238 112 252 141 219 141 218 112 Circle -16777216 true false 234 174 42 Rectangle -7500403 true true 181 185 214 194 Circle -16777216 true false 144 174 42 Circle -16777216 true false 24 174 42 Circle -7500403 false true 24 174 42 Circle -7500403 false true 144 174 42 Circle -7500403 false true 234 174 42 turtle true 0 Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210 Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105 Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105 Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87 Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210 Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99 wheel false 0 Circle -7500403 true true 3 3 294 Circle -16777216 true false 30 30 240 Line -7500403 true 150 285 150 15 Line -7500403 true 15 150 285 150 Circle -7500403 true true 120 120 60 Line -7500403 true 216 40 79 269 Line -7500403 true 40 84 269 221 Line -7500403 true 40 216 269 79 Line -7500403 true 84 40 221 269 x false 0 Polygon -7500403 true true 270 75 225 30 30 225 75 270 Polygon -7500403 true true 30 75 75 30 270 225 225 270 @#$#@#$#@ NetLogo 5.0 @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ @#$#@#$#@ default 0.0 -0.2 0 1.0 0.0 0.0 1 1.0 0.0 0.2 0 1.0 0.0 link direction true 0 Line -7500403 true 150 150 90 180 Line -7500403 true 150 150 210 180 @#$#@#$#@ 0 @#$#@#$#@