How to write piecewise function in netlogo for agent simulation? - netlogo

I'm doing Multi agent simulation using Netlogo, but in Netlogo, there is no suitable math expression for defining a piecewise function.
Anyone knows how to solve this ?
Many thanks!

to-report unitstep [#x]
report ifelse-value (#x < 0) [0] [1]
end
Edit:
If you want steps at multiple points, you could do this:
to-report n-steps [#x]
let steps [1 2 3]
let n 0
foreach steps [
set n (n + unitstep (#x - ?))
]
report n
end

I think it is best to write it functionally as a to-report
this snippet may help
to-report thing [X]
ifelse x < 10 and x > 5 [report 3][report x ^ 2]
end

Related

Multiple mutually exclusive events and probabilities in netlogo

consider the following 5 events that can occur in netlogo,
[a b c d e f]
Each event has a specific probability of occurring.
Say [0 0 0.3 0.5 0.1 0.1],
that is, p(a) = 0, p(b) = 0, p (d) = 0.5
One (and only one event)must occur . How do I model it in Netlogo.
What i did:
ask turtles
[
if random-float 1 < 0
[EventA]
if random-float 1 < 0.5
[EventD] ; and so on
]
But with this approach, sometimes no event will occur or sometimes more than 1.
Short answer: This is a classic use case for "roulette-wheel" selection.
You can use the NetLogo RND extension to do this, or roll your own following the Lottery example in the model library.
More:
The method abstracts the probabilities to weights, so any set of values from a list or from an agentset can be used; the probability of selection is the ratio of the individual value to the sum of all values in the set or list.
It does not require the set or lists to be sorted, and is scalable to any number of items.
You can write it to produce either the list index of the selected value, or a related value (like an agent or a value from another list).
It can be used for both with-replacement and without-replacement selection from the set.
Without-replacement can be done either by removing individuals from the selection list/set or by setting the selection weight/value of an individual to 0 once it is selected(use a copy of the real values if the selection is repeated.)
Link to NetLogo RND Extension
Simple roll-your-own example:
;; List weight has values to consider
;; Returns the index of the selected item
To RW-Select [ weight ]
Let last-index length weight
Let total sum weight
Let index 0
Let cumulative 0
Let rnd random-float total
While [cumulative <= rnd and index < last-index]
[
Set cumulative cumulative + item index weight
Set index index + 1
]
Report (index - 1)
End
For this, I suggest using just a single random-float between 0 and 1, saving it and then evaluating every probability based on that single number. The trick here is summing up your probabilities. If it is not p(a), check if it is p(a) + p(b). If it is not p(b), check if it is p(a) + p(b) + p(c) etc. In using this method, each option will have its own probability chance of being the chosen option and since the sum of all probabilities is 1, there is always 1 probability that will be chosen.
I use ifelse to evaluate this so option 2 is only considered is option 1 is rejected, option 3 only if 1 and 2 are rejected and so on. Normally ifelse only has 2 options but by including brackets around the entire thing, you can give it as many options as you want.
to go
let options ["a" "b" "c" "d" "e" "f"]
let probabilities [0 0 0.3 0.5 0.1 0.1]
let the-number random-float 1
show the-number
(ifelse
the-number < sum sublist probabilities 0 1 [show item 0 options]
the-number < sum sublist probabilities 0 2 [show item 1 options]
the-number < sum sublist probabilities 0 3 [show item 2 options]
the-number < sum sublist probabilities 0 4 [show item 3 options]
the-number < sum sublist probabilities 0 5 [show item 4 options]
the-number < sum sublist probabilities 0 6 [show item 5 options]
)
end
In your case, this would result in:
to go-2
let x random-float 1
(ifelse
x < 0 [show "a"] ;p(a) = p(x < 0) = 0
x < 0 [show "b"] ;p(b) = p(0 =< x < 0) = 0
x < 0.3 [show "c"] ;p(c) = p(0 =< x < 0.3) = 0.3
x < 0.8 [show "d"] ;p(d) = p(0.3 =< x < 0.8) = 0.5
x < 0.9 [show "e"] ;p(e) = p(0.8 =< x < 0.9) = 0.1
x < 1.0 [show "f"] ;p(f) = p(0.9 =< x < 1.0) = 0.1
)
end
First Edit:
Autogenerating this cumulative lists can for example be done using a map procedure. Here each new value of incremented-probabilities is the sum of the probability and all those that came before it.
let probabilities n-values 20 [0.05]
let incremented-probabilities (map [[this-probability index] -> sum sublist probabilities 0 (index + 1) ] probabilities range length probabilities)
show incremented-probabilities
Second Edit:
Now if you have a variable/high number of different options, you might not want to manually write this entire ifelse structure. Luckily Netlogo has the run primitive which allows you to read the content of a string and treat is as a command.
In the following example, I use foreach and word to, one by one, add an ifelse condition for each different option.
to go-3
let outcomes range 20
let probabilities n-values 20 [0.05]
let additive-probabilities (map [[this-probability index] -> sum sublist probabilities 0 (index + 1) ] probabilities range length probabilities)
let the-number random-float 1
show the-number
; Create your big ifelse code block as a string
let ifelse-string "(ifelse"
(foreach outcomes additive-probabilities [ [outcome probability] ->
set ifelse-string (word
ifelse-string
"\n the-number < "
probability
" [show "
outcome
" ]"
)
])
set ifelse-string word ifelse-string "\n)"
print ifelse-string
; Now run the string as if it was code
run ifelse-string
end
Lastly, you can take a look at "Lottery Example" in the models library. It looks a lot simpler than what i did here.
Thank you for posting the answers. The solution i used was to use cumulative probabilities.
let probabilities [0 0 0.3 0.5 0.1 0.1]
let cum-pmf partial-sums probabilities ; returns [0 0 0.3 0.8 0.9 1]
let n random-float 1
report length filter [ [?1] -> ?1 < n ] cum-pmf ; indexing starts at 0
and the function partial-sums is
to-report partial-sums [lst]
report butfirst reduce [[result-so-far next-item] -> lput (next-item + last
result-so-far) result-so-far] fput [0] lst
end

Working with index positions on a list in Netlogo

I'm struggling with the following problem using these variables:
set variablex .5
set threshhold-list [0 .3 .6]
set variable-list [0 0 1]
I have three agenttypes 0,1,2 that correspond to the index position of threshhold-list and variable-list. So Agent 0 has threshold 0 and variable 0, Agent 1 has threshold .3 and variable 0, and Agent 2 has threshold .6 and variable 1.
What I'd like to do is check if any agent has a threshold greater than zero and less than variablex. If so, update that agent's variable on the variable list to variablex. That is, for the variables above I'd like to run logic that produces a new variable-list like this one:
variable-list [0 .5 1]
But if variablex was .7, it would produce [0 .7 .7].
I've got some code I've been hacking away at but I feel like it's way more complicated than the problem and so I'm wondering if someone could point me in the right direction. Thanks so much!
There are a few different ways to approach the problem, but if I was in your situation, I would first write a small reporter that gives me the value that should be stored at each index:
to-report new-value [ i ]
let t item i threshhold-list
report ifelse-value (t > 0 and t < variablex)
[ variablex ] ; the variable's new value should be variable x
[ item i variable-list ] ; the variable's value should not change
end
Once you have that, you can use either foreach or map to change your variable list:
to update-variables-with-foreach
foreach range length variable-list [ i ->
set variable-list replace-item i variable-list new-value i
]
end
to update-variables-with-map
set variable-list map new-value range length variable-list
end
Here is a somewhat verbose test to check that both versions would give you the expected results:
globals [
variablex
threshhold-list
variable-list
]
to test
clear-all
set threshhold-list [0 .3 .6]
set variablex .5
set variable-list [0 0 1]
update-variables-with-foreach
print variable-list
set variablex .5
set variable-list [0 0 1]
update-variables-with-map
print variable-list
set variablex .7
set variable-list [0 0 1]
update-variables-with-foreach
print variable-list
set variablex .7
set variable-list [0 0 1]
update-variables-with-map
print variable-list
end
That being said, as much as I think it is fun to play with lists, I think you are approaching your problem in a very unnetlogoish way.
NetLogo's world is a world of turtles and patches and links, not a world of arrays and indices and numbers.
You could do something along the lines of:
globals [
variable-x
]
turtles-own [
threshhold
variable
]
to setup
clear-all
set variable-x .5
(foreach [0 .3 .6] [0 0 1] [ [t v] ->
create-turtles 1 [
set threshhold t
set variable v
]
])
ask turtles [ update-variable ]
ask turtles [ show variable ]
end
to update-variable ; turtle procedure
if threshhold > 0 and threshhold < variable-x [
set variable variable-x
]
end
I don't know what you're ultimately trying to achieve, but if I could offer general advice, it would be to try to embrace to NetLogo mindset. Every time you're tempted to use an index of some kind in your code, take a step back and think again: there is probably a better (as in "more netlogoish") way to do it.

Sort nested list

I found this code to sort nested list.
to-report test
let z [[2 3] [1 9] [3 1] ]
report sort-by [(first ?1) < (first ?2)] z
end
What is first ?1 and first ?2 in this formula. It says that they are not defined as variables.
Are you perhaps using NetLogo v6.0? Your code works in v5.3.1, but v6.0 uses anonymous reporters. It would look like:
to-report test
let z [[2 3] [1 9] [3 1] ]
report sort-by [[list1 list2] -> first list1 < first list2] z
end
Charles

Random sized array and exactly three ones in it

Good morning,
I need to create a list of [0,1], which length is defined by the user (global variable). There is an easy solution for this:
set listInd (list n-values numOfInd [random 2])
But I need to make sure, that the list has exactly three ones in it and they are placed on random positions. Is there a way to do this?
Regards.
You can create 3 random numbers (indices) and then create a list with 1 on the positions defined by this index list:
to-report rand-list[n k]
let ind-list n-of k n-values n [?]
report n-values n [ifelse-value (member? ? ind-list) [1][0]]
end
Usage:
show rand-list 10 3
; result:
; [0 1 0 0 0 0 1 0 0 1]
An alternative to bergant's solution would be to gather the desired amount of ones and zeros, then mix them together randomly:
to-report rand-list [n k]
let zeros n-values (n - k) [0]
let ones n-values k [1]
report shuffle sentence zeros ones
end

“Expecting a constant value” error when constructing a NetLogo list

I am currently working to create a pictorial representation of the Levy C-Curve in NetLogo using an IFS construction scheme. I have found two functions which describe how to iteratively map the locations of two turtles and should result in the desired curve after thousands of iterations. Here is my code so far:
;;;;;; some useful complex operations
; to take re(z) of a complex number a + bi inputed as the list of coordinates [a b]
to-report re [z]
report first z
end
; to take im(z)
to-report im [z]
report last z
end
; to multiply two complex numbers
to-report complex_mul [z1 z2]
report list (re z1 * re z2 - im z1 * im z2)
(re z1 * im z2 + im z1 * re z2)
end
; to add complex numbers
to-report complex_add [z1 z2]
report list (re z1 + re z2)
(im z1 + im z2)
end
; to dilate complex numbers by a scalar fraction
to-report complex/real [z1 real]
report list (re z1 / real)
(im z1 / real)
end
; to initialize
to setup
ca
setup-turtles
reset-ticks
end
; create 2 turtles located at the initial set of points {0, 1}
to setup-turtles
crt 2
ask turtle 0 [ setxy 0 0]
ask turtle 1 [ setxy 1 0]
ask turtles [ pd]
end
; to create the first function to transform the turtle's location
to-report nextz_1 [z]
report complex/real (complex_mul [1 -1] z) 2
end
; to create the second function to transform the turtle's location
to-report nextz_2 [z]
report complex_add [1 0]
(complex/real (complex_mul [1 1]
(complex_add z [-1 0]))
2)
end
; finally we are creating the Levy Curve
to levy
ask turtles [ run one-of (list task setxy re (nextz_1 [xcor ycor]) im (nextz_1 [xcor ycor])
task setxy re (nextz_2 [xcor ycor]) im (nextz_2 [xcor ycor])
)
]
end
However, I'm receiving an error message in my "levy" code block where I call re (nextz_1 [xcor ycor]) etc., saying that NetLogo is expecting a constant value in place of xcor and ycor.
How would I fix this issue?
At http://ccl.northwestern.edu/netlogo/docs/faq.html#listexpectedconstant the NetLogo FAQ says:
If a list contains only constants, you can write it down just by putting square brackets around it, like [1 2 3].
If you want your list to contain items that may vary at runtime, the list cannot be written down directly. Instead, you build it using the list primitive.
You actually got this right in some other places in your code, but in the levy procedure, you need to replace e.g. [xcor ycor] with list xcor ycor.
To NetLogo, [xcor ycor] looks like a reporter block, not like a list.