Trouble with bracket placement and the ifelse and let commands in Netlogo - if-statement

I am having trouble with bracket placement and the ifelse and let commands in Netlogo.
I have a variety of different conditions relating to patches-own (envi) and turtles-own (niche-opt, niche-range) variables that determine a local-variable (multi), that will then be used to determine the probability of reproduction.
Turtles have a variable niche-opt, if this matches the patch variable envi then the local variable multi = 1
If niche-opt != envi but envi is within niche-opt +- niche-range (turtle variable, integer ranging from 1 - 3) then multi = 0.8
And finally if envi is outside niche-opt +- niche-range then multi = 0.2
So the local variable "multi" can be one of three values (1,0.8 or 0.2), which is then multiplied with a turtles-own variable (trait-2) and used to determine the probability of hatch occurring.
My issue is that in the line of code:
if random-float 100 < (multi * trait-2 * 100)
comes up with the error "nothing named multi defined". I am sure the issue is to do with my bracket placements as let creates a local variable, but I cannot figure out if I need to add more brackets or just move the ones I have.
to go
ask turtles [
reproduce
]
end
to reproduce
ifelse niche-opt = envi
[let multi 1]
[ifelse envi >= (niche-opt - niche-range) and envi <= (niche-opt + niche-range)
[let multi 0.8]
[let multi 0.2]
]
if random-float 100 < (multi * trait-2 * 100)
hatch 1
end

It is probably simplest to use ifelse-value:
to reproduce
let multi ifelse-value (niche-opt = envi)[1] [
ifelse-value (envi >= (niche-opt - niche-range) and envi <= (niche-opt + niche-range)) [0.8][0.2]
]
if random-float 100 < (multi * trait-2 * 100) [hatch 1]
end
Untested.

Related

Chemotaxis in NetLogo

I have made a gradient, and I am quite unsure as to how I can make my turtle(s) attracted to one end and also behave a different way. For instance, from light blue to dark blue. Dark blue would be where the food is (chemoattractant), and in this zone, the bacterias would prefer to run randomly or be more energetic. While, in the light blue area, there would be fewer turtles and their movements would be slow or "tumbling."
Overall, how do I make the turtles sense the chemoattractant or the gradient in the patch?
If pcolors were floating point you could just search the immediate neighbors and use
ask turtles [ uphill pcolor ]
but that won't work if the gradient is subtle. The turtles might just sit there.
If you store a floating-point patch variable "exact_color" , say, the next code will work but the angle of motion is always some multiple of 45 degrees.
ask turtles [ uphill exact_color]
So if you generalize the search to a larger radius to determine the local gradient,
this would work:
let neighborhood patches with [ distance myself <= search_radius]
let p max-one-of neighborhood [exact_color]
if [exact_color] of p > exact_color [ face p move-to p]
Here's a working implementation that assigns the color gradient then tracks it.
globals [ scentXC scentYC search_radius ] ;; location of center of maximum scent
patches-own [ exact_color ];
to setup
clear-all
print ("This assumes the world does not wrap");
;; decide to put center of attraction at ( 14, 7 )
set scentXC 14;
set scentYC 7;
;; search a larger radius for gradient since it may be low
set search_radius 5;
color_code_patches
;; next line can visually check work so far
;; ask N-of 20 patches [ set plabel pcolor]
create-turtles 10 [ setxy random-pxcor random-pycor set size 2 set shape "arrow" pen-down];
reset-ticks
end
to go
;; ask turtles [ uphill pcolor ] ;; fails because the gradient is too low
;; following works but the angle of motion is always a multiple of 45 degrees
;; ask turtles [ pen-down uphill exact_color] ;; move one step uphill
;; the following searches a larger neighborhood for the uphill direction
ask turtles
[
;; set search_radius 1.45 to simply search neighbors, ie "uphill exact_color"
let neighborhood patches with [ distance myself <= search_radius]
let p max-one-of neighborhood [exact_color] ;; or neighbors4
if [exact_color] of p > exact_color [ face p move-to p]
]
end
to color_code_patches
no-display
ask patches [
let blueness 0 ;; initialize to make the interpreter happy
let dist distancexy scentXC scentYC
ifelse (dist <= 1) [ set blueness 250 ]
[ set blueness (250 / dist ) ]
set exact_color blueness;
set blueness round blueness;
;;set pcolor [ 0 0 blueness] ;; for unknown reason this doesn't work so more complex
let color_assign ( word "set pcolor [ 0 0 " blueness " ] ")
run color_assign
]
display
end

Netlogo: Nested if/ifelse statements

Building my first ABM using Netlogo and have a problem involving ifelse statements and how to use them. I'm modelling agents response to flooded properties. The concepts are as follows:
If an agent is flooded, they will consider adopting protective measures (if they haven't already).
If an agent has adopted protective measures, and are flooded, the success of the measure is calculated.
My code is as follows:
to process-property
let $random-flood-number random-float 1
ask properties [
set flood-damage-list-consequent replace-item 1 flood-damage-list-consequent (item 1 flood-damage-list-initial * (1 - PLP-reduction))
set flood-damage-list-consequent replace-item 2 flood-damage-list-consequent (item 2 flood-damage-list-initial * (1 - PLP-reduction))'
ifelse $random-flood-number < probability-flooding
[
set flooded? TRUE
set number-of-times-flooded (number-of-times-flooded + 1)
if plp-adopted? != TRUE [
calculate-adoption-intention
]
]
[
set flooded? FALSE
]
]
ask properties with [plp-adopted? = TRUE] [
plp-reliability-analysis
]
end
to plp-reliability-analysis
if plp-abandoned? = TRUE [stop]
if flooded? = TRUE [
if number-of-times-flooded > 1 [
let plp-reliability-factor 0.77 ;;This variable represents the probability of success that Manual PLP will offer full reduction in damage. Taken from JBA (2012;2014).
ifelse random-float 1 < plp-reliability-factor
[
set plp-deployed-successful? TRUE
set PLP-reduction 0.25
set successful-flood-damage-reduction (sum flood-damage-list-initial * PLP-reduction)
]
[
set plp-deployed-successful? FALSE
set PLP-reduction 0.9
set unsuccessful-flood-damage-reduction (sum flood-damage-list-initial * PLP-reduction)
calculate-abandonment-intention
]
]
]
end
I have written the following code as an error check, which i keep getting:
if flooded? = FALSE and plp-deployed-successful? = TRUE [error["Properties should only deploy PLP when they are flooded"]]
I believe the problem lies in the ifelse statements in "plp-reliability-analysis" procedure. I'm new to Netlogo and am confused as to when to use an 'if' or 'ifelse' statement. If someone could explain and have a look at the above code i'd be very grateful.
Thanks,
David
The difference between if and ifelse is that:
if is used when you want to run some piece of code only under certain conditions
ifelse is used when you want to run some piece of code under some condition and a different piece of code if the condition is not met.
Have a look at this shortened version of your code. Note that I moved the opening bracket to the beginning of the line to line up the start and end of code blocks. I also put end bracket on the same line for very short code blocks, but the bracketing is the same as yours.
to process-property
let $random-flood-number random-float 1
ask properties
[ ifelse $random-flood-number < probability-flooding
[ set flooded? TRUE ]
[ set flooded? FALSE ]
]
ask properties with [plp-adopted? = TRUE]
[ plp-reliability-analysis
]
end
to plp-reliability-analysis
if flooded? = TRUE
[ if number-of-times-flooded > 1
[ let plp-reliability-factor 0.77
ifelse random-float 1 < plp-reliability-factor
[ set plp-deployed-successful? TRUE ]
[ set plp-deployed-successful? FALSE ]
]
]
end
You draw a random number and assign it to the variable $random-flood-number. Then you ask every property agent to compare that number to the value of probability-flooding. However, you never draw a new random number. So if it's true for one property, it will be true for all the properties. Given it is a flood model, that is presumably intentional as all houses are equally affected by flooding.
Imagine that a low number is drawn and they all get flooded. All the ones with plp-adopted? are then sent to the plp-reliability-analysis procedure. For all of them, the variable flooded? is true so the code block is run.
The first line is if number-of-times-flooded > 1. The first time a flood occurs, the number-of-times-flooded is changed from 0 to 1. That will fail the test (did you mean to use >= instead of > ?) and the remainder of the code will not be run. It will simply jump to the end bracket.
[ let plp-reliability-factor 0.77
ifelse random-float 1 < plp-reliability-factor
[ set plp-deployed-successful? TRUE ]
[ set plp-deployed-successful? FALSE ]
]
But for the second and later code, it will run and 77% of the properties will have the plp recorded as successful, and the others set to unsuccessful.
So, how do you end up with some properties having the combination of false flood? and true plp-deployed-successful?.
Now jump forward in time and 2 (or more) floods have occurred. A flood has just happened, so 77% of the properties with plp-adopted? have true plp-deployed-successful? This time, there is not a flood and all properties have flooded? set to false. Those with plp-adopted? are sent to the plp-reliability-analysis procedure. However, flooded? is now false so the code block does not run and they retain their values of plp-deployed-successful? from the previous run through.

if loop does not work logically! in netlogo

I have two agents, customers and manufacturers. Each of these turtles have a number of variables which some of them are defined global to be able to be assigned to agents of another type. I have defined this : If at the end of the year, the purchases of product 1 is higher than both products 2 and 3, that product is distributed in 3 more stores. The problem is that the loop does not work logically. What are defined in the commands are happening while reporter is not true!!
ask manufacturers [
if (product1purchases > product2purchases) and (product1purchases > product3purchases) [
set storesavailability storesavailability + 3
set Brandd 1
set color red
]
Why when the condition defined in for if is not true, the commands are executed?
Thanks
They aren't. You can prove that to yourself by adding print statements, like this:
ask manufacturers [
let _cond ((product1purchases > product2purchases) and (product1purchases > product3purchases))
print (word "_cond is " _cond)
if (_cond) [
print (word "within branch, _cond is " _cond)
set storesavailability storesavailability + 3
set Brandd 1
set color red
]
]

Creating lists based on operations on turtle-own variables

I have 3 turtles and each has a size variable. I want to create a list of dimension 3 which will basically be % support size of each turtle with respect to the total size. List should look like
[turtle1-size / sum[size] of all turtles
turtle2-size / sum[size] of all turtles
turtle3-size / sum[size] of all turtle]
I know there are turtles-own and patches-own list but that will only contain the list of the turtle/patch names itself right?
Thanks, appreciate the help.
Regards
Here's one solution:
to-report proportions
let total-size sum [size] of turtles
report (list [size / total-size] of turtle 0
[size / total-size] of turtle 1
[size / total-size] of turtle 2)
end
let's try it:
observer> clear-all
observer> create-turtles 3 [ set size who ]
observer> show proportions
observer: [0 0.3333333333333333 0.6666666666666666]
Looks right to me.

Speedy test on R data frame to see if row values in one column are inside another column in the data frame

I have a data frame of marketing data with 22k records and 6 columns, 2 of which are of interest.
Variable
FO.variable
Here's a link with the dput output of a sample of the dataframe: http://dpaste.com/2SJ6DPX
Please let me know if there's a better way of sharing this data.
All I want to do is create an additional binary keep column which should be:
1 if FO.variable is inside Variable
0 if FO.Variable is not inside Variable
Seems like a simple thing...in Excel I would just add another column with an "if" formula and then paste the formula down. I've spent the past hours trying to get this and R and failing.
Here's what I've tried:
Using grepl for pattern matching. I've used grepl before but this time I'm trying to pass a column instead of a string. My early attempts failed because I tried to force grepl and ifelse resulting in grepl using the first value in the column instead of the entire thing.
My next attempt was to use transform and grep based off another post on SO. I didn't think this would give me my exact answer but I figured it would get me close enough for me to figure it out from there...the code ran for a while than errored because invalid subscript.
transform(dd, Keep = FO.variable[sapply(variable, grep, FO.variable)])
My next attempt was to use str_detect, but I don't think this is the right approach because I want the row level value and I think 'any' will literally use any value in the vector?
kk <- sapply(dd$variable, function(x) any(sapply(dd$FO.variable, str_detect, string = x)))
EDIT: Just tried a for loop. I would prefer a vectorized approach but I'm pretty desperate at this point. I haven't used for-loops before as I've avoided them and stuck to other solutions. It doesn't seem to be working quite right not sure if I screwed up the syntax:
for(i in 1:nrow(dd)){
if(dd[i,4] %in% dd[i,2])
dd$test[i] <- 1
}
As I mentioned, my ideal output is an additional column with 1 or 0 if FO.variable was inside variable. For example, the first three records in the sample data would be 1 and the 4th record would be zero since "Direct/Unknown" is not within "Organic Search, System Email".
A bonus would be if a solution could run fast. The apply options were taking a long, long time perhaps because they were looping over every iteration across both columns?
This turned out to not nearly be as simple as I would of thought. Or maybe it is and I'm just a dunce. Either way, I appreciate any help on how to best approach this.
I read the data
df = dget("http://dpaste.com/2SJ6DPX.txt")
then split the 'variable' column into its parts and figured out the lengths of each entry
v = strsplit(as.character(df$variable), ",", fixed=TRUE)
len = lengths(v) ## sapply(v, length) in R-3.1.3
Then I unlisted v and created an index that maps the unlisted v to the row from which it came from
uv = unlist(v)
idx = rep(seq_along(v), len)
Finally, I found the indexes for which uv was equal to its corresponding entry in FO.variable
test = (uv == as.character(df$FO.variable)[idx])
df$Keep = FALSE
df$Keep[ idx[test] ] = TRUE
Or combined (it seems more useful to return the logical vector than the modified data.frame, which one could obtain with dd$Keep = f0(dd))
f0 = function(dd) {
v = strsplit(as.character(dd$variable), ",", fixed=TRUE)
len = lengths(v)
uv = unlist(v)
idx = rep(seq_along(v), len)
keep = logical(nrow(dd))
keep[ idx[uv == as.character(dd$FO.variable)[idx]] ] = TRUE
keep
}
(This could be made faster using the fact that the columns are factors, but maybe that's not intentional?) Compared with (the admittedly simpler and easier to understand)
f1 = function(dd)
mapply(grepl, dd$FO.variable, dd$variable, fixed=TRUE)
f1a = function(dd)
mapply(grepl, as.character(dd$FO.variable),
as.character(dd$variable), fixed=TRUE)
f2 = function(dd)
apply(dd, 1, function(x) grepl(x[4], x[2], fixed=TRUE))
with
> library(microbenchmark)
> identical(f0(df), f1(df))
[1] TRUE
> identical(f0(df), unname(f2(df)))
[1] TRUE
> microbenchmark(f0(df), f1(df), f1a(df), f2(df))
Unit: microseconds
expr min lq mean median uq max neval
f0(df) 57.559 64.6940 70.26804 69.4455 74.1035 98.322 100
f1(df) 573.302 603.4635 625.32744 624.8670 637.1810 766.183 100
f1a(df) 138.527 148.5280 156.47055 153.7455 160.3925 246.115 100
f2(df) 494.447 518.7110 543.41201 539.1655 561.4490 677.704 100
Two subtle but important additions during the development of the timings were to use fixed=TRUE in the regular expression, and to coerce the factors to character.
I would go with a simple mapply in your case, as you correctly said, by row operations will be very slow. Also, (as suggested by Martin) setting fixed = TRUE and apriori converting to character will significantly improve performance.
transform(dd, Keep = mapply(grepl,
as.character(FO.variable),
as.character(variable),
fixed = TRUE))
# VisitorIDTrue variable value FO.variable FO.value Keep
# 22 44888657 Direct / Unknown,Organic Search 1 Direct / Unknown 1 TRUE
# 2 44888657 Direct / Unknown,System Email 1 Direct / Unknown 1 TRUE
# 6 44888657 Direct / Unknown,TV 1 Direct / Unknown 1 TRUE
# 10 44888657 Organic Search,System Email 1 Direct / Unknown 1 FALSE
# 18 44888657 Organic Search,TV 1 Direct / Unknown 1 FALSE
# 14 44888657 System Email,TV 1 Direct / Unknown 1 FALSE
# 24 44888657 Direct / Unknown,Organic Search 1 Organic Search 1 TRUE
# 4 44888657 Direct / Unknown,System Email 1 Organic Search 1 FALSE
...
Here is a data.table approach that I think is very similar in spirit to Martin's:
require(data.table)
dt <- data.table(df)
dt[,`:=`(
fch = as.character(FO.variable),
rn = 1:.N
)]
dt[,keep:=FALSE]
dtvars <- dt[,strsplit(as.character(variable),',',fixed=TRUE),by=rn]
setkey(dt,rn,fch)
dt[dtvars,keep:=TRUE]
dt[,c("fch","rn"):=NULL]
The idea is to
identify all pairs of rn & variable (saved in dtvars) and
see which of these pairs match with rn & F0.variable pairs (in the original table, dt).