calculating with the values of links - performance

I need to calculate a connection value between myself and all of my nearPersons which uses among others the trust value of the link. However, getting the trust values of all links and using these in the computation slows down the running time. I did not succeed to find another way to do it more efficiently. Any suggestions would be highly appreciated!
breed [persons person]
undirected-link-breed [connections connection]
connections-own [trust]
persons-own
[
nearPersons
familiarity
]
to setup
clear-all
setupPersons
setupConnections
updateConnections
reset-ticks
end
setupPersons
create-persons 1000
[
set color black
set grouped false
setxy random-xcor random-ycor
]
end
to setupConnections
ask persons [create-connections-with other persons]
ask connections [ set trust 0.4]
end
to updateConnections
while [(count persons with [grouped = false] / 1000) > 5]
[
let highlyTrusted n-of (2 + random 9) (persons with [grouped = false])
ask highlyTrusted
[
ask my-out-connections with [member? other-end highlyTrusted] [set trust 0.6]
set grouped true
]
]
end
to go
getNearPersons
calculateConnection
forward 1
end
to getNearPersons
ask persons [ set nearPersons other persons in-cone 3 360 ]
end
to calculateConnection
ask persons with [nearPersons != nobody]
[
ask nearPersons
[
let degreeOfTrust [trust] of in-connection-from myself
]
]
end

Here is the model using agentsets of trust rather than links. I think that it will give you identical results, as long as there are only those two trust levels. I made a few other changes in the code - in particular your original while statement would never run as it was written (the quotient was always 1). Most are simply matters of style. Let me know if this is not what you need. Still not a speed demon, about 5 seconds per tick with 1000 persons, but a lot faster than the link version. Note that nPersons is a global so that I could play around with it.
Charles
globals [nPersons]
breed [persons person]
persons-own
[
nearPersons
Trusted
unTrusted
familiarity
grouped
]
to setup
clear-all
set nPersons 1000
ask patches [ set pcolor gray ]
setupPersons
updateConnections
reset-ticks
end
to setupPersons
create-persons nPersons
[
set color black
set grouped false
setxy random-xcor random-ycor
]
ask persons [
set Trusted no-turtles
set unTrusted persons
set familiarity 1
]
end
to updateConnections
while [(count persons with [grouped = false] / nPersons) > 0.2]
[
let highlyTrusted n-of (2 + random 9) (persons)
; so persons can be in more than one trust group and treat all trust groups equally?
ask highlyTrusted
[
set Trusted other highlyTrusted
set grouped true
]
]
end
to go
ask persons [ getNearPersons ]
calculateConnection
ask persons [ forward 1 ]
tick
end
to getNearPersons
ask persons [ set nearPersons other persons in-radius 3 ]
end
to calculateConnection
ask persons with [any? nearPersons]
[
let affiliation []
ask nearPersons
[
let degreeOfTrust ifelse-value (member? myself Trusted) [0.6] [0.4]
; let degreeOfTrust [trust] of in-connection-from myself ;;this line causes netlogo to run very slowly
set affiliation lput (degreeOfTrust * familiarity) affiliation
]
]
end

I had to make a few modifications of your code to make it run, I've included it below. But I believe the real problem is just the scale of what you are doing. With 1000 persons, there are approximately half a million links that you are repeatedly polling, and given the size of your world, the number of nearPersons for each person is likely quite large. Do you really need 1000 persons in your model, and/or do you really need every person to be connected to every other person? The number of links goes up exponentially with the number of persons.
breed [persons person]
undirected-link-breed [connections connection]
connections-own [trust]
persons-own
[
nearPersons
familiarity
grouped
]
to setup
clear-all
setupPersons
show "persons setup"
setupConnections
show "connections setup"
updateConnections
show "connections updated"
reset-ticks
end
to setupPersons
create-persons nPersons
[
set color black
set grouped false
setxy random-xcor random-ycor
]
end
to setupConnections
ask persons [create-connections-with other persons]
ask connections [ set trust 0.4]
end
to updateConnections
while [(count persons with [grouped = false] / 1000) > 5]
[
let highlyTrusted n-of (2 + random 9) (persons)
ask highlyTrusted
[
ask my-out-connections with [member? other-end highlyTrusted] [set trust 0.6]
set grouped true
]
]
end
to go
ask persons [ getNearPersons ]
show mean [count nearPersons] of persons
ask persons [ calculateConnection ]
show "got Connections"
ask persons [ forward 1 ]
tick
end
to getNearPersons
ask persons [ set nearPersons other persons in-cone 3 360 ]
end
to calculateConnection
ask persons with [nearPersons != nobody]
[
let affiliation []
let idx 0
ask nearPersons
[
let degreeOfTrust [trust] of in-connection-from myself ;;this line causes netlogo to run very slowly
set affiliation insert-item idx affiliation (degreeOfTrust * familiarity)
set idx idx + 1
]
]
end

Related

Using "myself" to change variables

I have 200 turtles who can be either sender or receiver of a message and are connected to each other in a random network. I am asking receivers to see if there are senders connected to them and if so, their knowledge value that is a set with 3 values regarding 3 items gets updated with knowledge value of the neighbor added to them.
the problem is myself can be easily used to be assigned to a variable, but in my case it cannot be used to change items in a pre-defined set as I encountered an error saying that this was not something I could use set on!
Any suggestions?
Thanks
Turtles-own [
knowledgeValue
receiver?
sender?
]
;Network is already constructed and turtles are connected.
to go
ask turtles [
set knowledgeValue []
]
ask turtles [
repeat 3 [
set knowledgeValue lput random-float 1 knowledgeValue
]
]
ask turtles with [receiver?] [
ask (turtles-on neighbors) with [sender?] [
; the knowledge of receiver gets updated
set [item 0 [knowledgeValue]] of myself [item 0 [knowledgeValue]] of myself + knowledgeValue
]
]
end
The problem is not myself. The problem is that you are trying to set a value in a list, whereas set is used for variables. Have a look at replace-item instead.
And you need to do something like ask myself set ....
If you must do it this way, here's one option. With this setup:
turtles-own [
knowledgeValue
receiver?
sender?
]
to setup
ca
resize-world -3 3 -3 3
set-patch-size 70
ask patches [
sprout 1 [
set receiver? false
set sender? false
ifelse random-float 1 > 0.5 [
set receiver? true
set color green
set knowledgeValue [0 0 0]
] [
set sender? true
set color red
set knowledgeValue []
repeat 3 [
set knowledgeValue lput random-float 1 knowledgeValue
]
]
]
]
reset-ticks
end
This generates a world where all receivers start with [0 0 0] as their knowledgeValue list (to prove that senders are the ones adding value). Now, have all receivers get their neighbors with sender? to ask the asking receiver to update that receiver's list. I don't really like this solution but it sort of approaches the issue from the same tack that you outlined.
to option-1
ask turtles with [ receiver? ] [
; ask senders to ask 'myself' (receiver)
ask ( turtles-on neighbors ) with [sender?] [
ask myself [
; note that the second myself (below) actually refers to the 'sender'
set knowledgeValue replace-item 0 knowledgeValue ( item 0 knowledgeValue + item 0 [knowledgeValue] of myself)
]
]
]
end
One alternative would be to simply sum the values needed and add them directly:
to option-2
ask turtles with [ receiver? ] [
let my-senders ( turtles-on neighbors ) with [ sender? ]
if any? my-senders [
; get the sum of their item 0 knowledgeValue
let to-add sum [ item 0 knowledgeValue ] of my-senders
; add it to the knowledgeValue
set knowledgeValue replace-item 0 knowledgeValue ( item 0 knowledgeValue + to-add )
]
]
end

Dynamic layout additions in Rebol3

I would like to dynamically add a button to the layout of a view, with the actor causing this addition belonging to a button that is already part of the layout.
I started with this:
REBOL [title: "Dynamic Button Addition"]
tilesize: 60x60
curtile: 1
stylize [
p: button [
facets: [init-size: tilesize max-size: tilesize]
actors: [
on-action: [
++ curtile
append tiles compose [ p (to-string curtile) ]
print ? tiles/options/content
v/redraw
]
]
]
]
v: [
tiles: hgroup [ p "1" ]
]
view v
...which does not appear to have the value of tiles/options/content change with each click.
I can get it to change if make these changes:
append tiledata compose [ p (to-string curtile) ]
and
tiledata: [ p "1" ]
v: [
tiles: hgroup tiledata
However, this does not cause any change on screen. If I replace the last four lines with this:
v: view [
tiles: hgroup tiledata
]
...so that v is now the view rather than the view's layout, I get this error when I click:
** Script error: v has no value
** Where: actor all foreach do-actor unless do-face if actor all foreach do-actor if do-event do-event if do-event either -apply- wake-up loop -apply- wait forever try do-events if view do either either either -apply-
** Near: actor face :data
This makes sense to me, because v is not yet done being defined, until I exit the program, IIUC.
How, then, can I make changes to v before the program ends, but after it's been passed to view?
Not very nice, but working if you replace
v/redraw
with these two lines
unview/all
view v
And there is a real dynamic example on how to update a layout that has already be viewed
I will simplify it
stylize [
tbox: hpanel [
actors: [
on-make: [
append face/options [
content: [
]
]
do-actor/style face 'on-make none 'hpanel
]
]
]
]
view/across [
button "button 1"
on-action [
append-content test compose [
button ( join "button " 2 + length? test/gob)
]
]
test: tbox
]

Evaluating code blocks in Rebol3

I'm trying to improve the Sliding Tile Puzzle example by making the starting positions random.
There's a better way to do this--"It is considered bad practice to convert values to strings and join them together to pass to do for evaluation."--but the approach I took was to try to generate Rebol3 source, and then evaluate it. I have it generating correctly, I think:
random/seed now
arr: random collect [ repeat tilenum 9 [ keep tilenum ] ]
hgroup-data: copy {}
repeat pos 9 [
curtile: (pick arr pos)
append hgroup-data either curtile = 9
[ reduce "x: box tilesize gameback " ]
[ rejoin [ { p "} curtile {" } ] ]
if all [(pos // 3) = 0 pos != 9] [ append hgroup-data " return^/" ]
]
print hgroup-data
...outputs something like:
p "4" x: box tilesize gameback p "5" return
p "3" p "7" p "1" return
p "2" p "8" p "6"
...which if I then copy and paste into this part, works correctly:
view/options [
hgroup [
PASTE-HERE
]
] [bg-color: gameback]
However, if I try to do it dynamically:
view/options [
hgroup [
hgroup-data
]
] [bg-color: gameback]
...(also print hgroup-data, do hgroup-data, and load hgroup-data), I get this error:
** GUI ERROR: Cannot parse the GUI dialect at: hgroup-data
...(or at: print hgroup-data, etc., depending on which variation I tried.)
If I try load [ hgroup-data ] I get:
** Script error: extend-face does not allow none! for its face argument
** Where: either if forever -apply- apply init-layout make-layout actor all foreach do-actor unless -apply- apply all build-face -apply- apply init-layout make-layout actor all foreach do-actor if build-face -apply- apply init-layout make-layout actor all foreach do-actor unless make-face -apply- apply case view do either either either -apply-
** Near: either all [
word? act: dial/1
block? body: get dial...
However, if I use the syntax hgroup do [ hgroup-data ], the program runs, but there are no buttons: it appears to be somehow over-evaluated, so that the return values of the functions p and box and so on are put straight into the hgroup as code.
Surely I'm missing an easy syntax error here. What is it?
First, I would say it's better to construct a block directly, instead of constructing a string and converting it to a block. But if you really want to do that, this should do the trick:
view/options compose/only [
hgroup (load hgroup-data)
] [bg-color: gameback]

NetLogo - nelson-winter entrepreneur model works but very slow - can it be sped up?

I've been working on a NetLogo model simulating entrepreneurs based on Nelson-Winter model. In the model, every tick there is a Demand and Supply for some product,then the price=Demand/Supply, so every tick the entrepreneurs have a chance to set up a company and make money, the probability of setting uo a companies is effected by the revenue of other companies set up by the entrepreneurs in the same group, entrepreneurs in the same group share the same gamma and lambda,gamma decide the proportion of profit invested in R&D(innovation and imitation),the lambda decided the proportion of R & D funding invested in the innovation. The success of RD will enhance the production.Finally it will returned the result of companies averaged by group, the companies in the same group will have the same companyNO and same gamma and lambda.
This process seems to work fine but it runs exceedingly slow, to the point that I'm worried I won't be able to feasibly run many simulations. Any ideas on how to speed up this process? In the earlier version model without group the model works really fast, so I think the problem lies in the grouping. The model code is getting pretty long, so I just added the part related to the grouping. I can provide more code to someone if the problem seems to lie elsewhere. Any help would be much appreciated!
globals[
S;;aggregate supply
SafterDie
D;;aggregate demand
P;;price of demand,P=D/S
g b eta;;used for get demand
file1
file2
totalGamma
totalLambda
NO
]
breed [entrepreneurs a-entrepreneur]
breed [companies a-company]
entrepreneurs-own[
humanCapital
timesOfChuangYe
chuangYe?;;chuang ye mei de
gaiLv
renGamma
renLambda
renNO
]
companies-own[
humanCapital
tempHumanCapital;;20140516
oldHumanCapital
initialCap
initialTech
companiesNO
capitalK;;capital K,nedd money c*K
gamma;;money uesd for R&D
lambda;;money used for innovation in terms of imitation
lifeLength
RecentRevenue;;profit every tick
production;;production of the tick
profit
accumulatedInnovation
accumulatedImitation
]
to setup
foreach n-values NoOfgroup [?] [
set bigGamma (random-in-range 0.4 1);;money uesd for innovation
set bigLambda (random-in-range 0.1 1);;money used for innovation VS imitation
set NO (? + 1)
create-entrepreneurs numberOfentreprenursInEveryGroup [ entrepreneur-setup ]
]
to entrepreneur-setup ;; turtle procedure
set color red
set shape "line";;line
move-to one-of patches
set humanCapital random-in-range 0 1
set chuangYe? 0;;if Entrepreneurship,0 no,1 yes
set timesOfChuangYe 0;;Entrepreneurship times
set renGamma bingGamma
set renLambda bingLambda
set renNO NO
end
to ifChuangYe
ask entrepreneurs with [chuangYe? = 0]
[
let node1 self
set gaiLv 0;;probability of entrepreneurship
getProbabilitiOfEntrepreueur node1
if (random-float 1 <= gaiLv)[
set chuangYe? 1
set timesOfChuangYe (timesOfChuangYe + 1)
hatch-companies 1 [
set color yellow
set shape "house"
create-link-with node1 [set color yellow]
set humanCapital ([humanCapital] of node1);;!!!
set companyNO ([renNO] of node1)
set gamma ([renGamma] of node1);;money uesd for RD
set lambda ([renLambda] of node1);;money used for innovation VS imitation
set initialTech humanCapital
set tempHumanCapital humanCapital
set oldHumanCapital humanCapital
company-setup
]
]
]
end
to getProbabilitiOfEntrepreueur [node1]
ask node1[
let number renNO
let co1 no-turtles
let en1 entrepreneurs with [renNO = number];;get entrepreneur
ask en1 [
set co1 link-neighbors;;get company
]
let total 0
ask co1 [;;to link
if lifeLength != 0 [
let k lifeLength
let singleRevenue 0
if lifeLength >= 6 [set k 6]
foreach n-values k [?] [
set singleRevenue (singleRevenue + (item ? RecentRevenue)/ (? + 1))
];;RecentRevenue is a list to collect a company's profit of every tick
set total total + singleRevenue
]
]
set gaiLv (1 / 50 * total + 5 / 100)
;;show gaiLv
]
end
to imitation
let newH 0
ask companies[
set accumulatedImitation (accumulatedImitation + (1 - lambda)* gamma * profit)
if accumulatedImitation >= 0.3 * (capitalK ^ 3) [
let co2 companies with [companyNO = companyNo]
set newH max ([humanCapital] of co2)
if newH > humanCapital [set humanCapital newH set imNO imNO + 1]
set accumulatedImitation (accumulatedImitation - 0.3 * (capitalK ^ 3))
]
]
end

Detecting a mouse click / mouse up in NetLogo

Using mouse-down? for mouse actions in NetLogo often results in the action happening too many times. For example, if you want to let users click to create new turtles, you could hook a forever button up to a procedure like:
to add-turtle
if mouse-down? [
crt 1 [ setxy mouse-xcor mouse-ycor ]
]
end
The problem is that this usually results in many turtles being created per click. I'd like to do something like:
to add-turtle
if mouse-clicked? [
crt 1 [ setxy mouse-xcor mouse-ycor ]
]
end
Where mouse-clicked? is true right as the person clicks (right after they left up the mouse button).
Unfortunately, you do have to keep track of it yourself, but the good news is that its not hard.
The key is to create a global called mouse-was-down? that is set to true if mouse-down? was true in the last time your mouse-oriented procedure was called. Then mouse-clicked? can be defined as follows:
to-report mouse-clicked?
report (mouse-was-down? = true and not mouse-down?)
end
It seems to work well in conjunction with a central mouse-management procedure that calls the other click-based procedures. For example:
globals [ mouse-was-down? ]
to-report mouse-clicked?
report (mouse-was-down? = true and not mouse-down?)
end
to mouse-manager
let mouse-is-down? mouse-down?
if mouse-clicked? [
add-turtle
; Other procedures that should be run on mouse-click
]
set mouse-was-down? mouse-is-down?
end
to add-turtle
crt 1 [ setxy mouse-xcor mouse-ycor ]
end
Using the mouse-is-down? local variable keeps the behavior more consistent if the mouse button is released before mouse-manager finishes.
Hello probably this is a bit late for your purpose, but in case anyone has the same problem, this is how I solved this in my models for now.
to add-turtle
if mouse-down? [
crt 1 [ setxy mouse-xcor mouse-ycor ]
stop
]
end
The workaround here is to add a "stop" command to kill the "create-new-turtle" forever button. The only tradeoff is that you will have to press again to create another new turtle.
Bryan Head's answer didn't work for me, it still created multiple turtles in one click.
Alternative:
A (non-forever) button which does crt 1 [ setxy mouse-xcor mouse-ycor ] with action key A.
Now all you need to do to add a turtle is press or hold A with your left hand while mousing with your right hand.
Here is an alternative to Bryan's code, in case you want to perform an action as soon as the mouse button is clicked (instead of waiting until it's released):
globals [ mouse-clicked? ]
to mouse-manager
ifelse mouse-down? [
if not mouse-clicked? [
set mouse-clicked? true
crt 1 [ setxy mouse-xcor mouse-ycor ]
]
] [
set mouse-clicked? false
]
end

Resources