NetLogo - exchanging variable values across links or agentsets (not within breeds) - hyperlink

I am building a NetLogo model that tries to explain how agents find information they need to make a decision by bumping into other agents as they move about a space. There are three types of agents, each type has their own behavior rules and interact with their environment in different ways. The three types of agents, however, are all part of the same organization [Organization A].
The code below shows the breed names and the kinds of variables I'm using.
breed [Implementers Implementer];; Member of Organization A
breed [IMDeployeds IMDeployed];; Member of Organization A
breed [IMremotes IMremote];; Member of Organization A
... [other breeds]
Turtles-own [exchangeinfo holdinfo inforelevant infoarray
taskcomplexity done];; is an info exchange going to happen, does the
turtle have info, is info relevant, and then an array
extensions [array]
globals [complete routinemeeting]
I want to do three things:
1&2 Create a mechanism that joins the IMRemotes to the IMDeployeds and the IMDeployeds to the Implementers.
(I've already tried creating links - I'm not sure that the mechanism does what I want the third thing to do:)
3: Periodically check in with the agents that are linked together to cross-check variable values so that "information" can be "exchanged". Code I have for when agents are in the same space and can use "turtles-here" is below:
ask Implementers [
ifelse any? other Implementers [have-info-same-team] [change-location]
ifelse any? IMDeployeds-here [have-info-same-team] [change-location]
end
to have-info-same-team
ifelse any? turtles-here with [holdinfo > 0] [checkarray9] [change-
location]
end
to checkarray9
ifelse any? other turtles-here with [array:item infoarray 9 > 0]
[array:set infoarray 9 1 set holdinfo 1 checkarray8][checkarray8]
end
[etc, checking each position from 9 down to 0 in the array until you've gotten all the new information from that agent that you need]
When I try to ask my-links to do any of these things [so that the agents in the same organization, but different "functions, if you will, can have purposeful meetings rather than relying on being in the same space with each other to communicate], I'm told that the procedure is a "turtle only" procedure or that infoarray is a turtle-only variable.
Any help or suggestions greatly appreciated!

Rather than asking the links to do these things, you want to ask the turtles at the other end of the links. I don't know if you have created directed or undirected links, but something like
ask turtle-set [other-end] of my-out-links [do something]
or
ask my-out-links [ask other-end [do something]]
will make the ask of the turtles at the other end of the links to this turtle. (Note that [other-end] of my-out-links yields a list of turtles rather than a turtleset, thus the use of turtle-set to turn the list into a turtleset. my-out-links seems to work with both directed and undirected links. See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#my-out-links.)
Hope this helps,
Charles

Related

Google sheet function (sort by name)

So I have two csv files, one is the all member information, one is a poll event result,
which is like:
Member information:
[Member Name],[Member Tier]
Apple, Bronze
Banana, Silver
Cat, Gold
Poll event result:
[Member Name],[OptionA],[OptionB],[OptionC]
Apple,0,0,1
Banana,1,0,0
Cat,0,1,0
I want to do is weight the vote value with member's tier, for example, Cat is gold member so in this poll OptionB will win.
But the poll csv file is lack of member's tier parameter, so, I'm thinking to do a function like:
Create list "tier Bronze","tier Silver","tier Gold"
in member information file, loop for everyone, if tier match, add to that list
and then go to poll file, loop for everyone, if name match the name in tier list, mark them.
I'm not sure is this the right way, and how to do it, any help will be appreciated :^)
What you need is a vlookup function.
Take 2 lists with member name (as ID) in first left column and tier in 2nd and then use vlookup.
Put vlookup on the right part of your poll table and write:
=vlookup(ID location;range with poll results;2;false)
Then copy down vlookup formula
Or you can do it in more elegant way using Arrayformula:
=ArrayFormula(
ifna(
vlookup(E3:E;$B$3:$C;2;false)
)
)

Include a left joined has_many association with condition

There is an association query I seem to be unable to do without triggering a N+1 query.
Suppose I host Parties. I have many Friends, and each time a friend comes to a party, they create a Presence.
And so:
Presence.belongs_to :party
Presence.belongs_to :friend
Friend.has_many :presences
Party.has_many :presences
So far so good.
I want to obtain a list of every one of my Friends, knowing whether or not they are present at this Party, without triggering a N+1 query.
My dataset would look like this:
friends: [
{name: "Dave Vlopment", presences: [{created_at: "8pm", party_id: 2012}]},
{name: "Brett E. Hardproblem", presences: [nil]},
{name: "Ann Plosswan-Quarry", presences: [{created_at: "10pm", party_id: 2012}]},
...
]
and so on.
I have a lot of friends and do a lot of parties, of course. (This is of course a fictional example.)
I would do:
Friend.all.includes(:presence).map{ |them| them.parties }
# But then, `them.parties` is not filtered to tonight's party.
Friend.all.includes(:presence).map{ |them| them.parties.where(party_id: pid) }
# And there I have an N+1.
I could always filter at the Ruby layer:
Friend.all.includes(:presence).map{ |them| them.parties.select{ |it| it.party_id = party.id } }
But this works pretty badly with as_json(includes: {}) and so on. I'm discovering this is very error-prone as I'll be making calculations on the results.
And I make a lot of parties, you know? (still fictional)
If I where on the first query, I lose the left join:
Friend.all.includes(:presence).where(party: party)
I have no idea that tonight, Brett and a bunch of friends, who are always there, are absent. (this one is not guaranteed to be a fictional experience)
I will only see friends who are present.
And if I go through party, well of course I will not see who is absent either.
Now I know there are ways I can do this in SQL, and other ways we can wrangle around some Ruby to pull it together.
However, I'm looking for a "first-class" way to do this in Activerecord, without getting N+1s.
Is there a way to do this using only the Activerecord tools? I haven't found anything yet.
I'm not sure whether this meets your expectation about "first-class" way or not.
But you can use this approach to avoids N+1
# fetch all friends
friends = Friend.all
# fetch all presences. grouped by friend_id
grouped_presences = Presence.all.group_by(&:friend_id)
# arrange data
data = []
friends.each do |friend|
json = friend.as_json
json["presences"] = grouped_presences[friend.id].as_json
data << json
end
puts data
It only executes 2 queries
SELECT `friends`.* FROM `friends`
SELECT `presences`.* FROM `presences`

Count number of patches with specific value within specific clusters of patches

I am new to NetLogo and I am still struggling with the links between patches and agents. I am building a land-use change model, where the agents are farmers. The patches in my model have a "lotid-farmer" value (to know which patch belongs to which farmer; all of them together correspond to the farmer's farm) and a "land-use" value. I am trying to count how many "land-use = 1" patches I have in each "lotid-farmer" (farms) and assign that to a variable that the agents have called "forest-size". I have tried many different things, like this piece of code (which does not work):
(foreach lotid-farmer count patches [ land-use = 1 ] set forest-size )
I wonder if anyone could explain why this statement makes no sense and suggest something else that could work or a tutorial on how to loop in NetLogo with "foreach"? Thank you in advance.
lotid is a value. foreach requires a list and a command-task. Also, your set operator doesn't have a value associated with it.
Actually, I wouldn't use a foreach and just ask farmers to set the variable. I'm going to assume lotid-farmer is the who of the farmer.
ask farmers [
set forest-size count patches with [land-use = 1 and lotid-farmer = myself]
]

Search and group products by shops REDIS

I found this question about Group By in redis but actually does not solve my issue. I have a complex search of products, once I got the ones I am looking for I want to group them by their shops, because they must be showed in a map.
My actual implementation is as follow:
-A function which search products by a pattern, it return products ids as "product:id"
product_ids = search_products_by_indexing(pattern)
-A hash with name "selling" which contains product:id/shop:id as key/value.
shops = $redis.hmget("selling", *product_ids)
# this returns list of shops as "shop:id" which sell the given prodcuts
-Then I do an intersection of shops with another list to get only shops located in a given city.
result_shops = shops & $redis.smembers("shops:city_name")
# OR by redis
$zinterstore(tem_id, shops, $redis.smembers("shops:city_name"))
result_shops = $redis.zrange(temp_id, 0, -1)
-The only thing I still need is to get the searched products grouped by result_shops. or for example this could be a hash as shop:id/[product:id] as key/value (this is the final result, shop must be in the city and product match the pattern)
Is my solution suitable to this problem or maybe there is a better implementation to solve it? any suggestion will be very appreciated!!
UPDATE: One product belongs to only one shop and one shop can have many products.
-A hash with name "selling" which contains product:id/shop:id as key/value.
This usage of a Hash will only allow you to one shop:id per product:id, meaning only one shop can sell a given product... perhaps the value should be a concatenated list of shop:ids or even better - use a Set selling:product:id and store all your relevant shop:ids in it.
-Then I do an intersection of shops with another list to get only shops located in a given city.
IMO this is redundant as the intersect's results is always shops:city_name
-The only thing I still need is to get the searched products grouped by result_shops.
If you've taken my Set instead of a Hash suggestion, this can be done with:
ZINTERSTORE tem_id 2 shops:city_name selling:product:id
ZRANGE tem_id 0 -1

How can I iterate through a hash created with Rails' Hash#to_xml?

I'm working with thetvdb.com API to get episode listings for a show. In general, the XML format is something like:
<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
<Episode><EpisodeName>Bar</EpisodeName><EpisodeNumber>2</EpisodeNumber></Episode>
</Data>
What I do is to parse the XML using Hash.from_xml and then process the data. To iterate through the episodes, I do something like:
hash_data['Data']['Episode'].each do ...
This works great if there are multiple episodes. But if there's only one episode, the each method actually iterates through the hash entries for that single particular episode, rather than just running the each method once. That breaks all of my code following it.
I tried:
hash_data['Data']['Episode'].to_a.each do ...
with the same results. There must be a "right" way to do this?
UPDATE: I thought this question was fairly clear, but it appears people are confused by it. To clarify, I'm really trying to just iterate through the episodes and look at the contents. The data is initially received as XML, so in order to examine it in Ruby, I convert it to a hash using Hash.from_xml(xml_response).
In terms of "expected behaviour", take this example:
hash_data['Data']['Episode'].each do |e| { puts e['EpisodeNumber'] }
I would expect that given this initial data:
<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
<Episode><EpisodeName>Bar</EpisodeName><EpisodeNumber>2</EpisodeNumber></Episode>
</Data>
The output would be:
1
2
That works. However, if I'm given input like this:
<Data>
<Series>...</Series>
<Episode><EpisodeName>Foo</EpisodeName><EpisodeNumber>1</EpisodeNumber></Episode>
</Data>
I get a crash, because e['EpisodeNumber'] is not valid. It's not valid because in the case of only one episode, the each actually iterates through each key of the Hash (so the first value coming into the each block is a key-value pair of EpisodeName) instead of being an array of Hashes as it was when there was more than one element.
In other words, when there are multiple episodes, hash_data['Data']['Episode'] is an Array of Hash types. When there is only one episode, it's just a Hash. My code would work properly if, when there was one episode, it was still an Array, but with only one item in it. But that's not the case. How can I deal with this properly?
I hope that clears it up?
UPDATE 2: It's been requested that I post Hash#inspect for the returned data. Here it is for a show with a single episode:
{"Data"=>{"Series"=>{"id"=>"263752", "Actors"=>"||", "Airs_DayOfWeek"=>"Thursday", "Airs_Time"=>"10pm", "ContentRating"=>nil, "FirstAired"=>"2013-01-17", "Genre"=>"|Game Show|Reality|", "IMDB_ID"=>"tt2401129", "Language"=>"en", "Network"=>"TBS Superstation", "NetworkID"=>nil, "Overview"=>"Hosted by Robert Carradine and Curtis Armstrong, King of the Nerds is the ultimate nerd-off. The series will follow eleven fierce competitors from across the nerd spectrum as they set out to win $100,000 and be crowned the greatest nerd of them all.\n\nKing of the Nerds will take the glory of geekdom to a whole new level as the eleven competitors live together in \"Nerdvana.\" Each week, they must face challenges that will test their intellect, ingenuity, skills and pop culture prowess. In each episode, the nerds will first compete as teams and then as individuals, facing challenges that range from live gaming to a dance-off to life-sized chess. One competitor will be eliminated each week until one nerd stands alone as the ultimate champion off all things nerdy.", "Rating"=>nil, "RatingCount"=>"0", "Runtime"=>"60", "SeriesID"=>nil, "SeriesName"=>"King of the Nerds", "Status"=>"Continuing", "added"=>"2012-10-31 21:53:29", "addedBy"=>"348252", "banner"=>"graphical/263752-g2.jpg", "fanart"=>"fanart/original/263752-1.jpg", "lastupdated"=>"1357501598", "poster"=>nil, "zap2it_id"=>nil}, "Episode"=>{"id"=>"4428487", "Combined_episodenumber"=>"1", "Combined_season"=>"1", "DVD_chapter"=>nil, "DVD_discid"=>nil, "DVD_episodenumber"=>nil, "DVD_season"=>nil, "Director"=>nil, "EpImgFlag"=>nil, "EpisodeName"=>"Welcome to the Nerdvana", "EpisodeNumber"=>"1", "FirstAired"=>"2013-01-17", "GuestStars"=>nil, "IMDB_ID"=>nil, "Language"=>"en", "Overview"=>nil, "ProductionCode"=>nil, "Rating"=>nil, "RatingCount"=>"0", "SeasonNumber"=>"1", "Writer"=>nil, "absolute_number"=>nil, "filename"=>nil, "lastupdated"=>"1357501766", "seasonid"=>"504427", "seriesid"=>"263752"}}}
Notice that Episode is a Hash type.
Here it is for a show with more than one episode:
{"Data"=>{"Series"=>{"id"=>"220441", "Actors"=>"||", "Airs_DayOfWeek"=>"Saturday", "Airs_Time"=>"8:30PM", "ContentRating"=>"TV-PG", "FirstAired"=>"2010-12-25", "Genre"=>"|Children|Drama|", "IMDB_ID"=>"tt1765510", "Language"=>"en", "Network"=>"The Hub", "NetworkID"=>nil, "Overview"=>nil, "Rating"=>"7.0", "RatingCount"=>"1", "Runtime"=>"30", "SeriesID"=>nil, "SeriesName"=>"R L Stine's The Haunting Hour", "Status"=>"Continuing", "added"=>"2011-01-10 15:59:43", "addedBy"=>"66501", "banner"=>"graphical/220441-g.jpg", "fanart"=>"fanart/original/220441-1.jpg", "lastupdated"=>"1354439519", "poster"=>"posters/220441-1.jpg", "zap2it_id"=>nil}, "Episode"=>[{"id"=>"3453441", "Combined_episodenumber"=>"1", "Combined_season"=>"1", "DVD_chapter"=>nil, "DVD_discid"=>nil, "DVD_episodenumber"=>nil, "DVD_season"=>nil, "Director"=>nil, "EpImgFlag"=>"2", "EpisodeName"=>"Really You (Part 1)", "EpisodeNumber"=>"1", "FirstAired"=>"2010-10-29", "GuestStars"=>"|Bailee Madison|Connor Price|", "IMDB_ID"=>nil, "Language"=>"en", "Overview"=>"A girl named Lilly (Bailee Madison) is given her very own life-sized \"Really You\" doll which is named Lilly D.; because she is good at manipulating her dad. Lilly remains a spoiled brat, bragging about Lilly D, even going as far as ripping the leg off a friends doll, after the friend informs Lilly that \"Lilly D hates Lilly\". Soon after, strange events begin to occur which Lilly's mother accuses Lilly of doing; despite how Lilly maintains she is innocent, and that Lilly D is alive.", "ProductionCode"=>nil, "Rating"=>"8.0", "RatingCount"=>"1", "SeasonNumber"=>"1", "Writer"=>nil, "absolute_number"=>nil, "filename"=>"episodes/220441/3453441.jpg", "lastupdated"=>"1350772755", "seasonid"=>"393441", "seriesid"=>"220441"}, ...
Notice Episode is now an Array of Hash types.
It sounds like Rails' Array#wrap method would solve your problem. I believe this should work:
Array.wrap(hash_data['Data']['Episode']).each do ...
Documentation here.
Use Hash Key/Value Methods
Rather than Enumerator#each, you probably want to use Hash#each_key, Hash#each_value, or Hash#each_pair to iterate through your hash.

Resources