NetLogo: more than one boolean in ifelse-value - if-statement

for one variable in my System Dynamics Model in NetLogo i would like to have more than one boolean in my ifelse-value.
I tried it with the following code that I used as the expression for the variable.
(ifelse-value
quality = 100 [ 1.1 ]
quality = 80 [ 1.4 ]
quality = 60 [ 0.8 ]
[ 0.7 ])
I got the following error:
IFELSE-VALUE expected 3 inputs, a TRUE/FALSE, a reporter block and a reporter block.
What am I doing wrong?

Related

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.

Netlogo: How to transfer lists belonging to neighbours to a matrix?

A list called ownList2 consists of two parameters. Flockmates are all the neighbours in a given radius of the neighbour. I tried this code in version 6.0. But it doesn't work.
Basically, I want to put a list of equal dimension into a matrix. Is there something wrong I am doing? Or someone could improve the code piece?
ask turtles[set ownList2 (list who sensed)]
;sensed is sensor value of a turtle with respect to the patch.
;ownList2 is like a message of two bytes,
;first byte mentioning the identity of the itself
;second byte mentioning the value of the sensor.
ask turtles[
foreach (list flockmates)
[
i -> set m45 matrix:to-column-list ( list [ownList2] of i )
]
]
Result:
For turtle-0 with neighbours 1, 2, 3:
ownList2 ~ [1 200]
[2 400]
[3 900]
The m43 for turtle-0 should look like
[[1 200][2 400][3 900]]
Thanks for adding that information. Here is a toy example that might do what you need:
extensions [ matrix ]
turtles-own [ ownlist2 sensed m45 ]
to setup
ca
; Setup example turtles as per question
foreach [ 100 200 400 900 ] [
n ->
crt 1 [
while [ any? other turtles-here ] [
move-to one-of neighbors4
]
set sensed n
set ownlist2 ( list who sensed )
]
]
; Get the turtles to create matrices from the ownlists of
; sorted other turtles
ask turtles [
set m45 matrix:from-column-list map [ i -> [ ownlist2] of i ] sort other turtles
]
; Example output:
ask turtle 0 [
print "Turtle 0's m45:"
print matrix:pretty-print-text m45
]
reset-ticks
end
Output example:
Turtle 0's m45:
[[ 1 2 3 ]
[ 200 400 900 ]]

NetLogo sort list of agents by a specific value

I have a model with 5000+ farmers and several factories. Sometimes a new factory is built, at which point I want the factory to do the following:
Create a list with all farmers and then sort that list according to distance of farmer to the factory (from low to high).
I have tried doing this with a table,
ask factory 1 [ask farmers [set distance-to-factory distance myself]]
ask factory 1 [set a table:group-agents farmers [distance-to-factory]]
but then the resulting agentsets are not ordered from low to high or vice versa. Moreover, I want the factory to be able afterwards to ask single agents from the ordered table (or list) to do something:
After ordering the farmers by their distance-to-factory, I want the factory to be able to ask farmers from that list to deliver their goods (i.e. the closest farmer is asked first, but when it has no goods, the second closest farmer is asked and so on).
Your help is much appreciated!
You need to create an agent variable for the factory that stores the list of farmers in distance order. Here is a full example, run it and inspect a factory to convince yourself that it works.
breed [factories factory]
breed [farmers farmer]
factories-own [my-farmers]
to setup
clear-all
create-farmers 100
[ setxy random-xcor random-ycor
set color yellow
set shape "circle"
set size 0.5
]
create-factories 3
[ setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
]
reset-ticks
end
to initialise-factory
set my-farmers sort-on [distance myself] farmers
end
Look at the initialise-factory procedure. The sort-on primitive operating on an agentset returns a list. And the [distance myself] of ... is calculating the distance back to the factory (because the factory is doing the asking and is therefore myself). So the list is sorted by distance to the factory.
Once you have created the list, you use list procedures (eg the item primitive) to do the asking specific farmers.
There are indeed multiple factories and the distance-to-factory is to the most recently created factory, but the my-farmers list that each factory has doesn't change.
I already used the profiler extension on a previous version of the model and that one was very slow because of every factory asking each farmer every time (once a year) if they had goods:
let closest-farmer (min-one-of farmers with [status = 0] [distance myself])
That is why I thought of every factory creating a list of farmers from closest to furthest, so that factories can run through that list. Below you find a more elaborate piece of code, I hope this helps you to get a better image.
breed [factories factory]
breed [farmers farmer]
globals [
count-down
total-capacity-factories
price-goods
]
farmers-own [
area
goods-per-area
goods
distance-to-factory
status
]
factories-own [
my-farmers
goods-delivered
capacity
revenues-this-year
total-revenues
]
to setup
clear-all
create-farmers 1000 [
setxy random-xcor random-ycor
set area one-of [10 50 100]
set goods-per-area one-of [5 10 15]
set color yellow
set shape "circle"
set size 0.5
]
create-factories 20 [
setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
]
set market-demand-goods 250000
set total-capacity-factories sum [capacity] of factories
set count-down 11
reset-ticks
end
to go
if count-down = 11 [
change-market-demand
ask farmers [
set status 0
set goods 0
]
]
if count-down = 10 [
ask farmers [
sow-seeds
]
]
if count-down = 5 [
if market-demand-goods - [capacity] of one-of factories > total-capacity-factories [
build-factory
]
]
if count-down = 2 [
ask farmers [
harvest-goods
]
ask factories [
receive-harvested-goods
sell-goods
]
]
set count-down count-down - 1
if count-down = 0 [
set count-down 11
]
end
to initialise-factory
set capacity 10000
ask farmers [
set distance-to-factory distance myself
]
set my-farmers (sort-on [distance-to-factory] farmers)
end
to change-market-demand
let chance random 100
if chance < 33 [
set market-demand-goods market-demand-goods - 50000
]
if chance >= 33 and chance < 66 [
set market-demand-goods market-demand-goods + 10000
]
if chance >= 66 [
set market-demand-goods market-demand-goods + 50000
]
let chance2 random 100
if chance2 < 50 [
set price-goods price-goods + 1
]
if chance2 >= 50 [
set price-goods price-goods - 1
]
end
to sow-seeds
set color brown
end
to build-factory
loop [
if total-capacity-factories >= market-demand-goods [stop]
create-factory 1 [
setxy random-xcor random-ycor
set color red
set shape "house"
set size 2
initialise-factory
set total-capacity-factories (total-capacity-factories + [capacity] of myself
]
end
to harvest-goods
set goods area * goods-per-area
end
to receive-harvested-goods
let i 0
loop [
if goods-delivered >= capacity [stop]
let closest-farmer-with-goods (item i my-farmers)
ifelse [status] of closest-farmer-with-goods = 0 [
set goods-delivered + [goods] of closest-farmer-with-goods
ask closest-farmer-with-goods [
set status "goods-delivered"
]
]
[set i i + 1]
]
end
to sell-goods
set revenues-this-year goods-delivered * price-goods
set total-revenues total-revenues + revenues-this-year
end
#JenB, thanks for the help! I also found out that it can be done as follows:
hatch factory 1 [
ask farmers [set distance-to-factory distance myself]
set my-farmers (sort-on [distance-to-factory] farmers)
]
Then I designed the following code for asking from the my-farmers list:
let i 0
loop [
if goods-delivered > capacity [stop]
let closest-farmer-with-goods (item i my-farmers)
ifelse [status] of closest-farmer-with-goods = 0 [ (; aka goods are not delivered yet to another factory)
set goods-delivered + [goods] of closest-farmer-with-goods
]
[set i i + 1] ; *else*
]
But this makes the model quite slow. Do you know how to make this simpler?

IFELSE [Compare the length of two separate lists] [ACT]

Following my question yesterday, I was trying to implement the code with filter and length. I think I achieved the filter but now I need the agents to compare their list length with other agent (activities) list. Here is my code:
ask agentes [
set culture-tags n-values 17 [random 2]
set shared-culture (filter [ i -> i = 0 ] culture-tags) ;count 0s and
create shared-culture
]
end
to move-agentes
ask agentes [
let nearest-activity min-one-of (activities) [ distance myself ]
ifelse any? activities in-radius sight-radius with
[ length t-shared-culture = length shared-culture ] ;as many 0s in t-shared-culture (specified later in the setup for activities) as in shared-culture
[ face nearest-activity ]
[ rt random 40
lt random 40
fd 0.3
]
]
Netlogo prints the next error: "ACTIVITIES breed does not own variable SHARED-CULTURE error while activity 176 running SHARED-CULTURE".
I imagine the mistake must be here: [ length t-shared-culture = length shared-culture ] but I don't know how to make both lists to interact.

Netlogo : inequality doesn't work properly under foreach

It supposes to be a simple code, but I don't know why it doesn't work properly.
I want to change a color of non-white turtle back into white if a condition is fulfilled. I put inequality as the condition.
for example, if the amount of red turtle > = 5, then [ do something ].
No error message for the code, but I found that [ do something ] codes are executed before the condition is fulfilled. For example, it is executed when the amount of turtle is 1 or 4. And I also found that there are moments when it reach > = 5, [ do something] code is not executed.
Below is the code
to seize-value
ask consumers [set type-of-value ( list blue red green) ]
foreach type-of-value [
if count consumers with [color = ?] > = 5 [
let z consumers with [color = ?]
ask z [ set color white ]
ask consumers with [color = white] [set value? false]
ask one-of cocreation-patches [ sprout 1 [gen-prevalue]]
]]
end
I've tried using a single color, instead of a list of color (without - foreach) it doesn't work either.
Can anyone help with this?
Thank you
You have something like the following at the top of your code to set up type-of-value as an agent variable:
breed [ consumers consumer ]
consumers-own [ type-of-value ]
However, you are treating it as a global variable in your code. First you say ask consumers [set type-of-value ( list blue red green) ] to set the AGENT variable called type-of-value to the list of colours. But you end that ask [] statement before starting the foreach.
Unless the consumers have different lists of colours, what you really want is something more like this (untested). Note that I have also removed your multiple creations of the same agentset (for efficiency):
globals [ type-of-value ]
to setup
clear-all
...
set type-of-value ( list blue red green)
...
reset-ticks
end
to seize-value
*type "seize-value on tick " print ticks
foreach type-of-value
[ let changers consumers with [color = ?]
*print ?
*print count changers
if count changers >= 5
[ ask changers
[ set color white
set value? false
]
ask one-of cocreation-patches [ sprout 1 [gen-prevalue] ]
]
]
end
UPDATE for debugging I have added three lines that will output key information for debugging. They are marked with an asterisk (*). Add those lines (without the *) and look at the output.