I noticed, while playing with Pharo, that regardless of the way I type the code in playground, if I try to run it, but there is some problem, when the debugger opens it shows your code nicely indented.
For example, if I have this not particullary well indented program in playground:
| banditA banditB testBandits multiRun results |
banditA := [ 1.0 random <= 0.6 ifTrue: [ 1.0 ] ifFalse: [ 0.0 ] ].
banditB := [ 1.0 random > 0.6 ifTrue: [ 1.0 ] ifFalse: [ 0.0 ] ].
"Tests banditA and banditB n times each, to see which one is better."
testBandits := [ :n |
| A B |.
A := 0.0.
B := 0.0.
n timesRepeat: [ A := A + banditA value ].
n timesRepeat: [ B := B + banditB value ].
A > B
ifTrue: [ { A + B . banditA} ]
ifFalse: [ A < B
ifTrue: [ { A + B . banditB} ]
ifFalse: [ { A + B . { banditA. banditB } atRandom } ] ] ].
"Accumulate the results of size - 2 * nTests number of trials of winning
bandits, each preceded with a explore phase with 2 * nTests (half to each
bandit."
multiRun := [ :nTests :size |
| testResults sum |
sum := 0.0.
testResults := (testBandits value: nTests).
2 * nTests negated + size timesRepeat: [ sum := sum + (testResults at: 2) value ].
sum ].
"Average the returns of a thousand runs, to each even number of tests between 1 and
size = 1000."
results := (1 to: 500) collect:
[ :n | { 2*n. ((1 to: 1000) collect: [ :each | multiRun value: n value: 1000]) average}].
Transcript clear; show: 'Number of tests;Return'; cr.
results do: [ :each | Transcript show: (each at: 1); show: ';'; show: (each at: 2); cr ].
results sorted: [ :first :second | (first at: 2) > (second at: 2) ]
If I open the debugger in this code sample with Ctrl+Shift+D, the debugger shows me a nicely formated DoIt object, minus the comments:
DoIt
| banditA banditB testBandits multiRun results |
banditA := [ 1.0 random <= 0.6
ifTrue: [ 1.0 ]
ifFalse: [ 0.0 ] ].
banditB := [ 1.0 random > 0.6
ifTrue: [ 1.0 ]
ifFalse: [ 0.0 ] ].
testBandits := [ :n |
| A B |
A := 0.0.
B := 0.0.
n timesRepeat: [ A := A + banditA value ].
n timesRepeat: [ B := B + banditB value ].
A > B
ifTrue: [ {(A + B).
banditA} ]
ifFalse: [ A < B
ifTrue: [ {(A + B).
banditB} ]
ifFalse: [ {(A + B).
{banditA.
banditB} atRandom} ] ] ].
multiRun := [ :nTests :size |
| testResults sum |
sum := 0.0.
testResults := testBandits value: nTests.
2 * nTests negated + size
timesRepeat: [ sum := sum + (testResults at: 2) value ].
sum ].
results := (1 to: 500)
collect: [ :n |
{(2 * n).
((1 to: 1000) collect: [ :each | multiRun value: n value: 1000 ])
average} ].
Transcript
clear;
show: 'Number of tests;Return';
cr.
results
do: [ :each |
Transcript
show: (each at: 1);
show: ';';
show: (each at: 2);
cr ].
^ results sorted: [ :first :second | (first at: 2) > (second at: 2) ]
After some digging, I discovered there is a option to format source code inside the class browser, just by right-clicking source code, then choosing Source code > Format code:
But I couldn't find a way to do the same to source code inside playground, as the Source code > Format code option is not shown on right-click. If I try the keyboard shortcut Ctrl-T inside playground, it just erases whatever is selected. I could just copy code from playground into the browser, format it there, and then copy it back to playground, or could just open the debugger on the sample and then copy the nicely formated code into the playground, erasing the DoIt top line and the return symbol ^ from the expression in the last line, but that's not convenient. So I'd like to know if there is a proper way.
By the way, the code sample I used as a example is my attempt at simulating a instance of the Multi-armed bandit problem used in a psychological experiment described in the book Algorithms to Live By: The Computer Science of Human Decisions:
"Once you become familiar with them, it’s easy to see multi-armed
bandits just about everywhere we turn. It’s rare that we make an
isolated decision, where the outcome doesn’t provide us with any
information that we’ll use to make other decisions in the future. So
it’s natural to ask, as we did with optimal stopping, how well people
generally tend to solve these problems—a question that has been
extensively explored in the laboratory by psychologists and behavioral
economists. In general, it seems that people tend to over-explore—to
favor the new disproportionately over the best. In a simple
demonstration of this phenomenon, published in 1966, Amos Tversky and
Ward Edwards conducted experiments where people were shown a box with
two lights on it and told that each light would turn on a fixed (but
unknown) percentage of the time. They were then given 1,000
opportunities either to observe which light came on, or to place a bet
on the outcome without getting to observe it. (Unlike a more
traditional bandit problem setup, here one could not make a “pull”
that was both wager and observation at once; participants would not
learn whether their bets had paid off until the end.) This is pure
exploration vs. exploitation, pitting the gaining of information
squarely against the use of it. For the most part, people adopted a
sensible strategy of observing for a while, then placing bets on what
seemed like the best outcome—but they consistently spent a lot more
time observing than they should have. How much more time? In one
experiment, one light came on 60% of the time and the other 40% of the
time, a difference neither particularly blatant nor particularly
subtle. In that case, people chose to observe 505 times, on average,
placing bets the other 495 times. But the math says they should have
started to bet after just 38 observations—leaving 962 chances to cash
in."
I'd like to see if I could arrive at this figure of 38 as a optimal number, so I wrote this simulation. Arrived pretty close, this plot shows the results of one run:
This particular run resulted in a maximum at 34, quite close to 38. There is some variation between runs, as the curve gets a bit noisy in the top, but the maximum is consistently less than ten positions away of 38.
Related
I am having trouble using nested ifs in Netlogo to specify deer reproductive probabilities. Here is what I have come up with so far:
to reproduce-adult
let chance-fawn random-float 1.001
let chance-to-reproduce .9
let chance-for-one .3
let chance-for-two .4
let chance-for-three .02
if any? femadults [
ask femadults [
if random-float 1.001 < chance-to-reproduce [
if chance-fawn < chance-for-three
[set births (births + 3)
let new-offspring nobody
hatch-infants 3
[set new-offspring self set color red - 1 set size 1]
set offspring new-offspring]
if chance-fawn > chance-for-two
[set births (births + 2)
let new-offspring nobody
hatch-infants 2
[set new-offspring self set color red - 1 set size 1]
set offspring new-offspring]
if (chance-fawn > .02) and (chance-fawn < chance-for-one)
[set births (births + 1)
let new-offspring nobody
hatch-infants 1
[set new-offspring self set color red - 1 set size 1]
set offspring new-offspring]
]]]
end
Basically, the chance of a doe getting pregnant is 90%. So I want that if the doe gets pregnant, she either has 1, 2 or 3 fawns. The chance of having 1 fawn is 28%. The chance of having 2 fawns is 60%. The chance of having 3 fawns is 2%. The problem with my current code is that if "chance-fawn" is between .3 and .4, it is not accounted for in the if statements, when it should be part of the 60% of having 2 fawns. Is there a better way to do this, using either if statements or something else? Thank you!
You can do what you want with ifelse, but you may want to have a look at the rnd extension, as it simplifies this type of thing. Specifically, the weighted-one-of-list command allows you to make roulette wheel selection where you assign different weights to different options. For an example, look at this setup:
extensions [ rnd ]
globals [ fawn-probs ]
to setup
ca
crt 10 [
setxy random-xcor random-ycor
]
set fawn-probs [ [ 1 0.31 ] [ 2 0.67 ] [ 3 0.02 ] ]
set offspring-list-norm []
set offspring-list-alt []
reset-ticks
end
You've got a list called fawn-probs that groups the different probabilities to different birth events. Note that I've made them sum to 1 by dividing each by 0.9; as p._phidot_ pointed out, your original probabilities did not. Now, you can use rnd:weighted-one-of-list to have your turtles randomly choose the number of fawns, weighted appropriately, from the fawn-probs list.
to reproduce
ask turtles [
; If a spawning event occurs
if random-float 1 < 0.9 [
; Select the number of fawns to spawn based on the weighted
; probability list 'fawn-probs'
let num-to-spawn first rnd:weighted-one-of-list fawn-probs [ p -> last p ]
hatch num-to-spawn [
rt random 360
fd 1
]
]
]
end
Alternatively, if you want to have the 10% chance of no-birth bundled into the same list, you could skip the if random-float ... chunk and just do:
to reproduce-alternative
set fawn-probs [ [ 0 0.1 ] [ 1 0.28 ] [ 2 0.6 ] [ 3 0.02 ] ]
ask turtles [
let num-to-spawn first rnd:weighted-one-of-list fawn-probs [ p -> last p ]
hatch num-to-spawn [
rt random 360
fd 1
]
]
end
ok.. here's my drawing (not to scale) :
+---------+---------+---------+---------+---------+--------->
0.0 0.02 0.1 0.3 0.4 0.5
a number line.. after the 1st if, you covered :
+=========+---------+---------+---------+---------+--------->
0.0 0.02 0.2 0.3 0.4 0.5
on the 2nd if :
+=========+---------+---------+---------+=========+=========>
0.0 0.02 0.2 0.3 0.4 0.5
the 3rd if:
+=========+=========+=========+---------+=========+=========>
0.0 0.02 0.2 0.3 0.4 0.5
So, it is logical that your conditions DOESN'T covers 0.3 to 0.4 range. (:
Also note that if your random number generated is EXACTLY 0.02 for example.. the 1st if and the 3rd if will miss it too. unless you use something like <= or >=.
Hope that explains.. (:
I am working in Netlogo on a series of models making heavy use matrices. Briefly, the models include a number of state-variables for different breeds, where the state-variables are often stock-like items. As a simple example, consider the model:
extensions [ matrix ]
globals
[
]
turtles-own
[
n-items
stock-list
]
to setup
clear-all
reset-ticks
create-turtles 2
ask turtles
[
setxy random-xcor random-ycor
set n-items 10
let n-vars 3
set stock-list matrix:make-constant n-items n-vars [0] ; empty matrix
let stock-item n-values n-items [i -> i]
let stock-cost n-values n-items [ random-normal 10 2 ]
let stock-age n-values n-items [ random 50 ]
matrix:set-column stock-list 0 stock-item
matrix:set-column stock-list 1 stock-cost
matrix:set-column stock-list 2 stock-age
]
end
Here, each turtle's matrix stock-list is initialised as an empty matrix and then its columns filled in depending on the variables stock-item (id for stock), stock-cost and stock-age.
Imagine a go procedure that increments the stock age by one each time-step:
to go
ask turtles
[
let current-age matrix:get-column stock-list 1
let new-age map [x -> x + 1] current-age
matrix:set-column stock-list 2 new-age
]
tick
end
What I would like to do is an operation on stock-cost only if the age is greater than some value, e.g. 10
;; pseudo-code
for( i = 1 to I = number of items )
{
if ( stock-age[i] > 10 )
{
stock-cost[i] - 1
}
}
I know how to change the list of stock-cost conditional on its own values, using the map primitive, e.g.:
to decrease-stock-value
ask turtles
[
let current-cost matrix:get-column stock-list 1
set current-cost map [[?] -> ifelse-value (? > 10) [? - 1][?]] current-cost
matrix:set-column stock-list 1 current-cost
]
But my efforts to generalise this to using values in a different list to condition upon have failed.
Thanks for your help! Also, any insight onto whether this is a good approach to modelling state variables such as stocks would be useful.
I think I sorted it out using:
to decrease-stock-value
ask turtles
[
let current-cost matrix:get-column stock-list 1
let current-age matrix:get-column stock-list 2
let new-cost ( map [ [ a b ] ->
ifelse-value ( a > 10 ) [ b - 1 ] [ b ] ]
current-age current-cost
)
matrix:set-column stock-list 1 new-cost
]
end
I'm writing up a code in Netlogo that basically should do the following:
Amongst directed links, interact and seek out their cooperative behavior (coop_b).
Store coop_b in a list variable together with the time of the interaction (reputation_now)
Every interaction, add the reputation_now to a bigger list, reputation_h (reputation history)
Now, add a time-weight to the reputation, so that the more recently had interactions weigh more in the total reputation. I do this by dividing the encounter time of an interaction by the current time tick, then multiplying that with the coop_b to retrieve a weighted reputation for each interaction. This is stored in the list reputation_h_w (historic reputations weighted). The thing is, this list should be updated every time the members interact, so that earlier additions to the list are now updated to the new time tick. My hunch is this is where my code goes in the mist (problems depicted below the code section).
My code:
to horizontal_interact
ask members [
;set random example variable for coop_b
set coop_b random-float 5 ; coop-b stands for cooperation behavior
if ticks > 0 [
ask my-out-links [ ;there are directed links between all members
set reputation_now (list [coop_b] of end2 ticks) ;list of coop_b and encounter time
set reputation_h lput reputation_now reputation_h ; history of reputations, a list of all reputation_now recorded
foreach reputation_h [ x ->
let cooperative_behavior item 0 x
let encounter_time item 1 x
let reputation_now_w (list cooperative_behavior encounter_time (encounter_time / ticks ))
]
]
]
]
end
If I test the content of reputation_h and reputation_h_w with 2 members, I get:
reputation_h is the coop_b variable of the member and the tick of encounter
links> show reputation_h
(link 1 0):
[[4.0900840358972825 1]
[0.8885953841506328 2]
[0.47017368072392984 3]]
(link 0 1): [[3.6805257472366164 1]
[3.6805257472366164 2]
[3.4201458793705326 3]]
reputation_h_w (containing the member's coop_b variable, the encounter time and the encounter time divided by the ticks):
links> show reputation_h_w
(link 0 1): [[3.6805257472366164 1 1]
[3.6805257472366164 1 0.5]
[3.6805257472366164 2 1]
[3.6805257472366164 1 0.3333333333333333]
[3.6805257472366164 2 0.6666666666666666]
[3.4201458793705326 3 1]]
(link 1 0): [[4.0900840358972825 1 1]
[4.0900840358972825 1 0.5]
[0.8885953841506328 2 1]
[4.0900840358972825 1 0.3333333333333333]
[0.8885953841506328 2 0.6666666666666666]
[0.47017368072392984 3 1]]
The problem is that reputation_h_w doesn't make sense to me - firstly there's six inputs instead of three, and secondly, the encounter time (item 1) and the encounter time/ticks (item 2) is off.
What am I doing wrong here?
Not sure where you update reputation_h_w in your code, but I'm guessing that you are not resetting it to a blank list before running your foreach loop again. So, it's lput-ing the values at the end of the list, which is not blank anymore.
Example setup:
breed [ as a ]
as-own [ coop_b ]
links-own [ reputation_now reputation_history reputation_history_w]
to setup
ca
create-as 2 [
set coop_b who + 1
setxy random-pxcor random-pycor
]
while [ any? as with [ not any? my-in-links ] ] [
ask one-of as with [ not any? my-out-links ] [
create-link-to one-of other as with [ not any? my-in-links ] [
set reputation_now []
set reputation_history []
]
]
]
reset-ticks
end
Note that here I will set reputation_history [] right before the foreach chunk runs:
to interact
if ticks > 0 [
ask links [
set reputation_now ( list [coop_b] of end2 ticks )
set reputation_history lput reputation_now reputation_history
; reset reputation history to a blank list, as you are
; recalculating the weighted value at each tick
set reputation_history_w []
foreach reputation_history [ x ->
let behavior item 0 x
let encounter_time item 1 x
let fraction encounter_time / ticks
set reputation_history_w lput (
list behavior encounter_time fraction ) reputation_history_w
]
show ( word "Current reputation: " reputation_now )
show ( word "Reputation history: " reputation_history )
show ( word "Weighted history rep list: " reputation_history_w )
]
]
tick
end
As far as why your ticks are off, I'd guess it's because you are calling tick after you run your horizontal_interact procedure. With the example above, my output looks like:
(link 0 1): "Current reputation: [2 2]"
(link 0 1): "Reputation history: [[2 1] [2 2]]"
(link 0 1): "Weighted history rep list: [[2 1 0.5] [2 2 1]]"
(link 1 0): "Current reputation: [1 2]"
(link 1 0): "Reputation history: [[1 1] [1 2]]"
(link 1 0): "Weighted history rep list: [[1 1 0.5] [1 2 1]]"
even though the ticks read 3. If you run it with tick at the start of the procedure, that might sort out your expected output.
I have a sub-routing in my code where each patch is asked to pick its closest & farthest turtle based on certain conditions. I keep getting this error after a couple of ticks
OF expected input to be a turtle agentset or turtle but got NOBODY instead.
error while patch 0 30 running OF
called by procedure UPDATE-SUPPORT
called by procedure GO
called by Button 'Go'
There are two other routines where a turtle dies or is born depending on a few other metrics that are measured. I am not able to debug the code but what i have figured so far is that it happens after a turtle dies or is born.
Below is the code based on which the closest & farthest turtles are assigned at each tick.
to update-support
ask patches [
let old-total sum [my-old-size] of parties
set f-party []
set h-party []
set party-list (sort parties)
set voteshare-list n-values length(party-list) [ (([my-old-size] of party ? ) + 1 ) / ( old-total + 1 ) ]
set party-citizen-dist n-values length(party-list) [ ( distance party ? ) ^ 2 ]
set f-list n-values length(party-list) [ ( ( 1 / ( item ? voteshare-list ) ) * ( item ? party-citizen-dist ) ) ]
set f-index position (min f-list) f-list
set h-list n-values length(party-list) [ ( ( item ? voteshare-list ) * ( item ? party-citizen-dist ) ) ]
set h-index position (max h-list) h-list
set f ((-1) * (min f-list))
set h max h-list
set f-party lput item f-index party-list f-party
set h-party lput item h-index party-list h-party
set closest-party first f-party
set farthest-party first h-party
]
After a turtle dies, when I inspected the patch which was throwing the error, i found the word nobody as an element in the list. The error is highlighted to be in the Party ? section while creating the voteshare-list in the above code
When I inspected the patch throwing the error, Party-list which is the list with all the current parties sorted was showing this:
Party-list: [(party 0) nobody (party 2)]
and my f-party list just had [(nobody)]
Has anyone faced such a situation.?
Below is the death & birth routine:
to party-death
ask parties [if (fitness < survival-threshold and count parties > 2)
[ die
] update-support
]
to party-birth
ifelse (endogenous-birth? = true)
[ ask one-of patches with [distancexy 0 0 < 30]
[ if (random-float 1 < (kpi * 1000)) [sprout-parties 1 [initialize-party] ]]
[ create-parties 1 [set heading random-float 360 jump random-float 30 initialize-party] ]
update-support
end
I spent the morning trying to find an easy function (x,y) -> n that would number the patches like this
I was not successful. Do any of Y'all have any experience or suggestions?
Here is my take on it:
patches-own [ n ]
to setup
clear-all
resize-world -4 4 -4 4 ; so it looks better, but use any size you like...
create-turtles 1 [
set heading 180
foreach n-values count patches [ ? + 1 ] [
set n ?
if [ n = 0 ] of patch-left-and-ahead 90 1 [ left 90 ]
fd 1
]
die
]
ask patches [ set plabel n ]
end
Funny you should ask I also spent the morning doing the same thing. There is a function that uses the floor function but I remembered that this is netlogo
so I made a turtle do it for me.
with this procedure
to spin
let k 1
set t t + 1
repeat 2
[
lt 90
repeat t [fd 1 ask patch-here [set n k set k k + 1]]
]
end
and this code in the start up.
crt 1 [
set heading 0
repeat 41 [spin]
die
]
and of course
patches-own [n]
to call them in n order use
foreach sort-on [n] patches ask ? [ "the stuff you want them to do" ]