NetLogo: "with" command with multiple criteria - syntax

I want to use the "with" command to select turtles that are matching two criteria, X and Y. I don't know how to include the second criteria (Y) into the first bracket.
It looks like this:
ask other turtles with [X = 1 and Y=1] [
The "and" command is probably not the way to go, just so you understand what I am trying to achieve.
Sorry if this is a stupid question, I just can't figure it out.

that should work...
this code works:
ask patches with [pycor <= 1 and pxcor > 7] [ set pcolor 23]
sometimes netlogo has random compile issues, I'd try running it again or reopening your editor.

Related

Netlogo slow to get table value from indexed turtle

I am building a Netlogo model that includes a social diffusion component, and am running into a surprising performance issue using the Table extension.
For some context: in the model, each agent has a table of attitudes with a string key (e.g. "Environment") and a float value of -1 to 1. Each tick, agents update their attitude based on those of their contacts and a weight for each contact. To prototype I'm using the simple update rule for each contact:
a(t) = a(t-1) + w * [b(t-1) - a(t-1)]
Where a is the agent's attitude, b is the contact attitude, and w is the weight. Each agent has 5-10 contacts.
I have implemented this in two ways. The first uses links which performs decently. However, the memory footprint for this appears to get quite large as I scale up. Since the network is not dynamic, I am experimenting with implementing this as a table where keys are contact turtle IDs and values are weights (Strictly speaking, I create a list of turtle ids called "contacts" and a table of corresponding weights to avoid recreating the list each time I iterate). This appears to use much less memory with many agents but is unexpectedly an order of magnitude slower.
Here is a snippet of the network-based update:
ask my-in-links [
let neighborAttitude table:get [attitudes] of other-end "Environment"
let myAttitude table:get [attitudes] of myself "Environment"
let influence weight * (neighborAttitude - myAttitude)
set myAttitude myAttitude + influence
table:put [attitudes] of myself "Environment" myAttitude
]
And the table-based version:
foreach (contacts) [ i ->
let myAttitude table:get attitudes "Environment"
let neighborAttitude table:get [attitudes] of homeowner i "Environment"
let w table:get contactWeights i
let influence w * (neighborAttitude - myAttitude)
set myAttitude myAttitude + influence
table:put attitudes "Environment" myAttitude
]
From some testing it appears the big slowdown occurs from getting the neighborAttitude. If I comment out that line, getting and putting from the agent's attitude table seems just as fast as the network based block. So it seems to be finding the other turtle ("homeowner").
Is there something inherently really slow in NetLogo of looking up a turtle/agent by id? This seems like it should be basically free but I don't know what the data structure is for this under the hood.
This code is very not-NetLogo like so I am having some trouble parsing it and my comment/answer may have completely missed the point.
I don't understand the use of table at all for these lines:
ask my-in-links [
let neighborAttitude table:get [attitudes] of other-end "Environment"
You are starting with ask my-in-links. Presumably this is inside an ask turtles or similar block. So running the code first chooses a turtle, let's say that turtle has 5 links to other turtles. It hits this code and runs through each of those 5 links and creates a table with those 5 values that are somehow stored in a table with the key [attitudes] of other-end "Environment".
Assuming you have links (which you must to be able to use ask my-in-links) then a much more NetLogo-ish way of doing this is something like the following. Note that this is a full model, you can put it in an empty NetLogo model to run it.
turtles-own
[ myAttitude
myUpdatedAttitude
]
links-own
[ wgt
]
to setup
clear-all
create-turtles 20
[ setxy random-xcor random-ycor
set myAttitude -1 + random-float 2
]
; create a network
repeat 50
[ ask one-of turtles
[ create-link-to one-of other turtles
[ set wgt random-float 1 ]
]
]
reset-ticks
end
to go
type "average attitude: " print mean [myAttitude] of turtles
let w 0.4
; calculate next value and store until all calculated
ask turtles with [any? in-link-neighbors]
[ let wtd-diffs [([myAttitude] of other-end - [myAttitude] of myself) * wgt] of my-in-links
set myUpdatedAttitude (1 - w) * myAttitude + w * sum wtd-diffs
]
; make the change
ask turtles [ set myAttitude myUpdatedAttitude ]
tick
end
For each turtle in turn, this code constructs a list of the weighted difference in attitude values between the turtle and the turtles it is influenced by. So, if it has 5 in-link-neighbors, the wtd-diffs list will have 5 values. The next line calculates the total influence, storing it in a different value so all the calculations are done on the current value. Note that I haven't used exactly your equation as I wasn't sure how you were keeping it from simply growing uncontrollably.
I realise this doesn't answer your question about table performance, but I expect this approach will solve all your performance issues.
Right after submitting this I tried an experiment that confirms my suspicion, and I think resulted in an acceptable solution. It does turn out that simply asking turtles to look up "turtle i" is slow, and gets slower with an increasing number of agents.
I'm guessing that with of turtle i Netlogo is doing the equivalent of of turtles with [who = i] and must be iterating through a list of all turtles until it finds the matching ID. So as a test, using the table extension again I manually created a table of all turtles:
globals [turtleTable]
...
to initialize-turtleTable
set turtleTabletable:make
ask turtles [
table:put turtleTable who self
]
end
Then instead of of turtle i you can say of table:get turtleTable i. This is slightly more cumbersome syntax but could be cleaned up with a reporter. This ends up performing as originally expected, about on par with using links, but with around 25,000 agents uses nearly half the memory (<3GB vs >5GB), compared by completely exiting and relaunching NetLogo.

Xpath - is it possible to use more than one axes per query?

.//*[preceding::*[text()='Taco Salad'] and following::*[text()='Fajita Salad']]
I have text on this page and both queries for .//*[text()='Taco Salad'] and .//*[text()='Fajita Salad'] return what I expected. But I am a bit confused how to try to combine these with following and preceeding to grab some of the options nodes that present in the middle.
Does anyone have any working examples of using two axes?
I found this thread: combining XPATH axes (preceding-sibling & following-sibling) and tried to model my axes after it, but they don't seem to be valid xapths. Am I missing something obvious?
Unfortunately you haven't really told us what you want to achieve. Yes, you can use multiple axes; you can combine them in various different ways, depending on what result you want. So you need to explain what result you want. Using "and" at the top level simply tests whether both operands of the "and" select something.
Your question "does anyone have any working examples" isn't going to help. Yes, we can give you thousands of working examples, but it's entirely possible that none of them does what you want.
Here are some possible ways of combining two axis steps X and Y:
X/Y - select X, and from there, select Y
X and Y - return true if both X and Y select something
X or Y - return true if either X or Y selects something
X | Y - return the union of what X and Y select
X intersect Y - return the intersection of what X and Y select
The nearest you have come to a requirements statement is "grab some of the options nodes that present in the middle". That's hard to interpret without seeing your source document. It also might turn out to be a query that's easier in XPath 2.0 than in 1.0, so you really need to tell us which version you are using.
A working example of combining axes in single xpath can be:
//*[following-sibling::*[#class="bottom-notice"] and preceding-sibling::*[#name="new-answer"]]
It looks for the element form to write the answer on this page.

Use strings to create words and paths in Red language

I have strings in a namelist, that correspond to variables as well as field names in the application.
The function should read strings from namelist, add an 'f' to get field_names, and then put variable values in corresponding fields.
I tried following code, that does not give any error, but also does not work:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
As a general point: it is easy to turn strings into WORD!s (e.g. to-word "foo"). However, it can be tough to magically make that WORD! reference be bound to "the variable you meant". The wily reasons for this have to do with the fact that there is no scope. See:
Is there a overall explanation about definitional scoping in Rebol and Red
So what you are trying to do is going to be a little dodgy regardless. There are better ways. But to try to avoid un-asking the question, I'll explain what's happening here and how to fix it in the style you were attempting.
corrected version is for instructional purposes only. please do this another way.
compose rejoin [namelist/:i "f/text"]
REJOIN is applied to blocks, and merges the contents, with a result type loosely based on the first element. (It's a questionable operation, but historically popular in Rebol code.)
Since namelist/:i is a string, your REJOIN will produce a string...and this string will wind up being passed to COMPOSE. But COMPOSE is meant to be applied to BLOCK!s...and searches for parenthesized groups inside of it, evaluating them while leaving the rest of the code alone. It's a kind of templating system for blocks, with no effect on other kinds of input...so you'll get the same string out.
TO-SET-PATH is thus being fed a STRING! (e.g. "var1f/text"). I didn't even know that path conversion accepted strings. I find the behavior of this operation to be puzzling, because it apparently LOADs the string and then makes it the singular element of a length 1 SET-PATH!.
>> p: to-set-path "foo/bar"
== foo/bar: ;-- huh? really, did that work?
>> type? p
== set-path! ;-- ok, good, I guess.
>> length? p
== 1 ;-- wait, what?
>> type? first p
== path! ;-- a PATH! inside a SET-PATH!...?
>> length? first p
== 2
>> type? first first p
== word!
>> foo: 10
>> get first first p
== 10 ;-- well, at least it's bound
That's not making the kind of SET-PATH! you want; you want a SET-PATH! with 2 WORD! elements. Converting a BLOCK! to a SET-PATH! would be a way of doing this.
to-set-path compose [(load rejoin [namelist/:i "f"]) text]
Now we see COMPOSE being used correctly, where it will run the evaluation inside the parentheses and leave the text word alone. This produces a block with 2 elements in it, which is easily converted to a SET-PATH!. I'm using LOAD instead of TO-WORD to take care of some of the "magic" of connecting to an actual variable that plain word conversion would not do. But it's just a workaround--not a sure thing, and won't always be the answer to the problem.
But producing a SET-PATH! doesn't mean it runs. If I say:
s: to-set-word "x"
probe type? s
No SET-WORD! is executed, it's merely generated. And in this case, stored in the variable s. But if I hadn't stored it in a variable, the evaluation product would have just been thrown out...the way 2 is simply thrown out if I write 1 + 1 print "hi". To execute the SET-PATH!, you need to put it in a context where it will be composed into source and evaluated.
(Note: Ren-C has a primitive called EVAL which can do this on the fly, e.g. eval (quote x:) 10 will assign 10 to x.)
But in Red you'll need to do something like this:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
repeat i length? namelist [
do probe compose [
(to-set-path compose [(load rejoin [namelist/:i "f"]) text])
to-string
(load namelist/:i)
]
]
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
Now your outer COMPOSE is building an 3-element block, where the first element will be a SET-PATH!, the second a WORD! that was literally left alone to convert your integer to a string, and the third a WORD! that will be evaluated to the relevant integer. The DO of that block will have the assignment effect.
I changed your to-word namelist/:i to load namelist/:i. Again, for the reason I mentioned...TO-WORD alone doesn't put on a "binding".
I left a PROBE in there so you could see what is built and executed:
[var1f/text: to-string var1]
[var2f/text: to-string var2]
PROBE is a very helpful tool, which outputs its argument but also passes it through. You can insert it at various points in your code to get a better understanding of what's going on.
(Note: If you're wondering why I don't suggest writing a narrow EVAL-2 helper operation that only works for SET-PATH!, it's because such a thing exists with a better name. It's called SET. Try set (quote x:) 10 then print x. In fact, variants of this is how you'd actually want to do things... obj: make object! [a: 10] then set (in obj 'a) 20 then print obj/a. As I said, there's a lot better ways to go about what you're doing, but I tried to stay focused on doing it the-way-you-were-trying.)
This doesn't directly answer your question, though seems to address the problem you're facing. It uses the face/extra field to associate the fields to your value list:
namelist: [var1 var2]
var1: 5
var2: 10
process: function [][
foreach face lay/pane [
if find namelist face/extra [
face/text: form get to word! face/extra
]
]
]
lay: layout [
text "Values to appear here: "
field "a" extra 'var1
field "b" extra 'var2
button "Click" [process]
]
view lay
The only wrinkles are: it applies get to the words as they are set in the View spec—they need to be within the same context as the values you're working on, and—you can't get a lit-word! so have to change it to word! before getting.
Another approach if you want to contain your values in a map:
values: #(foo: 5 bar: 10)
process: function [container [object!]][
foreach face container/pane [
if find values face/extra [
face/text: form select values face/extra
]
]
]
view [
text "Values to appear here: "
field "a" extra 'foo
field "b" extra 'bar
button "Click" [process face/parent]
]
Step 1: refactor
Here is your code reformatted and print (1) statements added:
namelist: ["var1" "var2"]
var1: 5
var2: 10
process: [
print "process: start" ; (1)
repeat i length? namelist [
(to-set-path compose rejoin [namelist/:i "f/text"] (to-word namelist/:i))
]
print "process: end" ; (1)
]
lay: layout [
text "Values to appear here: "
var1f: field "a"
var2f: field "b"
button "Click" [do process]
]
view lay
When I run this in the console and press "Click", it gives the following:
process: start
process: end
So I know at least the button works
Step 2: debug with print
Now I can focus, moving print inside the code block:
process: [
repeat i length? namelist [
print (
to-set-path compose rejoin [
namelist/:i "f/text"
] (to-word namelist/:i)
)
]
]
Almost immediately I can see what's wrong here :
var1 ; expecting `var1f` here
var2 ;
Step 3: we need to go deeper with probe
Aside
Now, before I proceed further, notice that this code doesn't access
anything inside the view block (because it doesn't work!).
But the nice thing here is you could ignore this and come back to it later.
What you need is a way to access var1f/text programmatically
Keeping that in mind, here is a better way to phrase this question:
Step 3a: how to dynamically create objects with different names and set values to them?
var1f/text: 5
(given the code in step 2)
Now, I reach a conundrum here. This would probably be best asked as a different, simpler question.
I decided to continue assuming you accomplished this (there's another answer too)
Note
The important thing to take home in this step is the datatype Red view uses and what you're working with is the same thing: red objects.
There is no difference (all are instances of a simple face object)
Step 4: you're done! Or are you?
So you're able to create the gui you want for your work and you're done!
Right?
But then you ask yourself, is this the best way to do it?
What if you want to add some more of this, or something else entirely?
You have read the official gui docs especially the part about view engine
You've looked at examples of vid and adding view face objects manually
You've looked at the repo on github for sample code and small apps
You've even tried the old, but stable rebol2
But you still don't get it? Don't despair, this is normal.
A lot of stuff have names that are conceptually similar to what you are familiar in other languages but are different in subtle ways which tends to make them really different.
In the end tho, a lot is simpler than you'd think but stranger(having deeper implications)
tl;dr
Separate your view code from the rest so it's easier to debug
Use print, probe and dump-face to debug

How to compare the amount of turtles at different times (ticks) in Netlogo?

I´m trying to see how many turtles are added and eliminated from the simulation each tick.
I want to do something like this:
If (count turtles - count turtles in t-1) > 0
Then
[]
End
The model I´m trying to do that for is the team assembly model from the netlogo´s library.
If you want to keep records, you have to do it explicitly. Often global variables are used for this. E.g.,
globals [laggedCount]
to setup
ca
crt 25
end
to provideExample
set laggedCount count turtles
ask turtles [
if random-float 1 < 0.1 [die]
]
print laggedCount - count turtles
end
In this case, since the relevant code is in a single procedure, you could use a local variable (which is preferable). But to share such information across procedures you will either need to pass it explicitly or use a global variable. Finally, note that you could assign to this global a list to which you repeatedly append, so that you could store the entire history of values during your simulation. (Finally finally, if that's what you want, you could alternatively plot those values during the simulation and export the plot afterwards.)

while loop debugging in netlogo

I am having trouble understanding an error emerging from two consecutive while loops in a net logo project.
;;;;;;;;;;;;;;;;;;;;;;;;
;;; Global variables ;;;
;;;;;;;;;;;;;;;;;;;;;;;;
globals [it]
;;;;;;;;;;;;;;;;;;;;;;
;;; Breedin agents ;;;
;;;;;;;;;;;;;;;;;;;;;;
breed [houses house]
breed [firms firm]
;;;;;;;;;;;;;
;;; Setup ;;;
;;;;;;;;;;;;;
to setup
clear-all
reset-ticks
create-firms F
create-houses H
;; sets position of the firms in the space for better visualisation
set it 0
while [it < F ]
[ask firm it [
set color yellow
set heading it * 360 / F
fd 5
]
set it it + 1
]
;; sets position of the households in the space for better visualisation
set it 0
while [it < H ]
[ask house it [
set color yellow
set heading it * 360 / H
fd 15
]
set it it + 1
]
When I run the above code I get an error message
firm 0 is not a HOUSE
error while observer running HOUSE
called by procedure SETUP
called by Button 'Setup'
pointing at house it in the code.
Notice that when I only run the first while loop, everything works fine.
I guess there is something I do not understand in the use of while loops in net logo.
Why does the second while loop seem to consider that I am calling firms although I asked to call houses?
Is there a better way to implement while loops in net logo?
Many thanks in advance for you help
What's happening?
who numbers in NetLogo are assigned from the same sequence for all turtles, independently of their breeds. If you do:
create-firms 1
create-houses 1
Then you will have firm 0 and house 1, which you could also address as turtles. For example, in the command center:
observer> show turtle 0
observer: (firm 0)
observer> show turtle 1
observer: (house 1)
It makes sense to have unique identifiers like that, because the breed of a turtle is a very transient thing. It can be changed:
observer> ask firm 0 [ set breed houses ]
observer> show turtle 0
observer: (house 0)
The turtle has kept its who number despite the change of breed.
Why does the second while loop seem to consider that I am calling firms although I asked to call houses?
What you are doing is the equivalent of taking turtle 0 (which is a firm) and trying to cast it to a house. This is why NetLogo complains that firm 0 is not a house.
A better way to do it
Is there a better way to implement while loops in net logo?
Yes: don't use while! More seriously: using while is most often unnecessary. There is usually a better way to do things.
Also, in general, don't use who numbers for anything. If you want to deal with many turtles at once, use a turtle set. If you want to keep track of a turtle, store the reference to it directly (e.g., set my-firm one-of firms). If you find yourself wanting to use the who number, take a step back and rethink about your problem: there is almost certainly another way.
You want to do something with all your houses? Just ask them!
ask houses [
set color yellow
fd 15
]
There is one thing that the snippet above does not address, however: your requirement for evenly spaced turtles. But you can achieve this by using the create-ordered-<breeds> to create your turtles. With it, your entire setup becomes:
clear-all
create-ordered-firms F [
set color yellow
fd 15
]
create-ordered-houses H [
set color yellow
fd 15
]
But what if you really need an index?
But what if create-ordered-<breeds> did not exist, or if you wanted to do something similar that required some sort of index? You still don't need while: a combination of foreach and n-values will get you there:
create-houses H
(foreach sort houses n-values H [ ? * 360 / H ] [
ask ?1 [
set color yellow
set heading ?2
fd 15
]
])
(We use sort to turn the houses turtle set into a list, but [self] of houses works as well if you want them shuffled.)
That code may look weird at first, but it's actually a pretty common and useful pattern in NetLogo. It "zips" the thing you want to act on with the index that you want to assign to it. It also has a few nice advantages over a while loop: no "off by one" errors, no extra variable and no risk of forgetting to increment the counter or to accidentally mutate it.

Resources