limitation of forming subset in netlogo - netlogo

Dear Netlogo community,
Last week I posted the question on the same forum about forming subset from a set in netlogo. Here is the link.
How to form subset form a set of numbers in Netlogo
The problem with the above thread is that it wont give the subsets if the set contains more than 21 elements. It throws java heap space out of memory exception. I believe this is because the above thread stored all subsets in one list and eventually list of list reached to its maximum range and throws java heap space out of memory exception. Any help in this regard will be valuable.

A set with N elements has 2^N subsets. Computationally, you cannot do anything with all of them once N is big, but you can still pick from them randomly. Let's assume your N elements are in a list. Then you can pick a random subset:
to-report random-subset [#lst]
let _result []
foreach #lst [
if (one-of [true false]) [
set _result lput ? _result
]
]
report _result
end
Note that this is equivalent to picking a random number in [0..(2^N-1)] and then selection the subset "corresponding" to that number.
If you prefer a more functional approach, you can use
to-report random-subset02 [#lst]
report filter (task [one-of [true false]]) #lst
end

Here is code that runs a task on every subset as soon as that subset is generated, without accumulating all of the subsets in memory:
to foreach-subset [xs fn]
foreach-subset-helper [] xs fn
end
to foreach-subset-helper [prefix xs fn]
ifelse empty? xs
[ (run fn prefix) ]
[ foreach-subset-helper prefix butfirst xs fn
foreach-subset-helper lput (first xs) prefix butfirst xs fn ]
end
Sample run:
observer> foreach-subset [1 2 3] task print
[]
[3]
[2]
[2 3]
[1]
[1 3]
[1 2]
[1 2 3]
Tasks in NetLogo are documented at http://ccl.northwestern.edu/netlogo/docs/programming.html#tasks.

Related

How to find the largest network cluster?

"nw:weak-component-clusters" in the Networks extension will return a list of weakly connected agentsets. I would like to output the number of turtles in the biggest of these.
So
show nw:weak-component-clusters
observer: [(agentset, 15 turtles) (agentset, 20 turtles) (agentset, 16 turtles)]
would return 20.
Is there an easy way to do this please?
This isn't pretty but it will work:
to find_max
let my_list []
let my_max 0
let turt_list nw:weak-component-clusters
foreach turt_list [x -> ask x [set my_list lput count x my_list]]
set my_max max my_list
show my_max
end
There is a simpler approach using map:
to-report count-of-largest-cluster
report max (map count nw:weak-component-clusters)
end
map takes a reporter and a list as inputs, and reports a list whose items are the result of the input reporter being run for every item of the input list.
nw:weak-component-clusters is a list of agentsets, therefore map count nw:weak-component-clusters is a list of each agentset's count. Note that the parentheses in my solution are optional and only there for readability.

How to fix "Nothing named ? has been defined" error in NetLogo 6.0.4

I downloaded the modified random clusters code for generating neutral landscape models using the Millington's version of the modified random clusters approach in the NetLogo modeling commons. When I click the "generate-landscape" button, the "fill-landscape" procedure in the code causes a "Nothing named ? has been defined" error.
When I created the attached interface image and attempted to run the adjoining code below. The problem seems to be related to the question mark in the "occurrences" report function. The reduce function is not working as intended. Is there a work around for this? See interface, then code below:
ifelse ( any? neighbours with [ cluster != nobody ] ) ;; check if there are any assigned patches in neighbourhood
[
let covers []
ask neighbours with [ cluster != nobody ]
[
set covers fput cover covers ;;ask neighbours to add their covers to the list
]
let unique-covers remove-duplicates covers ;;create a list of unique covers
let max-cover-count -1 ;the number of neighbours with the maximum cover
let max-cover -1 ;the maximum cover
ifelse(length unique-covers > 1)
[
;if there is more than one unique-cover
foreach unique-covers ;for each of the unique covers
[
let occ occurrences ? covers ;count how many neighbours had this cover
ifelse(occ > max-cover-count) ;if the count is greater than the current maximum count
[
set max-cover ? ;set this as the dominant cover
set max-cover-count occ ;update the current maximum count
;---------------
to-report occurrences [x the-list]
report reduce
[ifelse-value (?2 = x) [?1 + 1] [?1]] (fput 0 the-list)
end
;---------------
The code is suppose to generate a neutral landscape model using the modified random clusters approach developed by Saura and Martinez-Millan (2000). However, the error "Nothing named ? has been defined" error the code from running smoothly. Looking forward to thoughts ...
The old ? syntax from NetLogo 5.x was replaced with the new -> syntax in NetLogo 6. See https://ccl.northwestern.edu/netlogo/docs/programming.html#anonymous-procedures
So, for example, in NetLogo 5, you would write:
foreach [0 1 2 3] [
print ?
]
in NetLogo 6, you write:
foreach [0 1 2 3] [ x ->
print x
]
A combination of Bryan's answer (first procedure) and the NetLogo Dictionary (second procedure) gives you the following. The comments indicate the new bits. Not tested.
ifelse ( any? neighbours with [ cluster != nobody ] )
[ let covers []
ask neighbours with [ cluster != nobody ]
[ set covers fput cover covers
]
let unique-covers remove-duplicates covers
let max-cover-count - 1 ; added a space around subtraction
let max-cover - 1 ; more spacing
ifelse(length unique-covers > 1)
[ foreach unique-covers
[ this-cover -> ; here's the new bit, calling ? 'this-cover'
let occ occurrences this-cover covers ; passes to the occurrences procedure
ifelse(occ > max-cover-count)
[ set max-cover this-cover ; using the name this-cover again
set max-cover-count occ
And for occurrences, you can take the procedure directly from the NetLogo Dictionary reduce example
to-report occurrences [#x #the-list]
report reduce
[ [occurrence-count next-item] -> ifelse-value (next-item = #x)
[occurrence-count + 1] [occurrence-count] ] (fput 0 #the-list)
end

Counting the number of different links

In my code all turtles own n-features represented by a n-tuple (a1,a2,...,an). where each ai can take values 0 or 1.
I have created some links between turtles. If two turtles share k-features (coordinate-wise matching) and there is a link between them then we call the link as k-link.
How can I find for each k (between 0 to n) how many k-links are there in total?
You don't tell us much about how you have structured your code, so I'm going to assume that your n-tuples are implemented as lists (which would make the most sense in NetLogo).
Here is a full example:
turtles-own [ a ]
links-own [ k ]
globals [ n ]
to setup
ca
set n 5
crt 10 [ ; create turtles with random feature lists
set a n-values n [ random 2 ]
]
ask turtles [ ; make a full network
create-links-with other turtles
]
ask links [ ; calculate k for all links
set k k-of-feature-lists ([a] of end1) ([a] of end2)
]
foreach n-values (n + 1) [ ? ] [ ; display number of k-links
show (word ? "-links: " count links with [ k = ? ])
]
end
to-report k-of-feature-lists [ a1 a2 ]
report length filter [?] (map = a1 a2)
end
Apart from k-of-feature-lists, this is fairly trivial code. What k-of-feature-lists does is to:
transform two lists of features into a single list of booleans containing a true value if the corresponding element is equal in both feature lists and false if it is not. This is accomplished using map and the concise task syntax for =;
filter the list of booleans to keep only the true values;
report the length of that filtered list, which is equal to the number of features that where the same in a1 and a2;
There are plenty of other ways to do that (some more efficient) but this one is nice and concise.

Calculate the number of common features an agent shares with an agentset

I would like to report a count of the number of common features (e.g. [1 8 4] is three features) an agent (target_turtle) shares with each agent in an agentset (neighbor_turtle). Any suggestions please?
For example: If the agent has the features [1 8 7] and an agent from the agent set has the features [1 7 8], they share one common feature i.e. 1 . The features 8 and 7 are not included as the order of the features is relevant.
The current error I get is: All the list arguments to FOREACH must be the same length.
Cheers,
Marshall
;; reporting overlap between two agents
to-report overlap_between [target_turtle neighbor_turtle]
let suma 0
ask neighbor_turtle
[
(foreach [feature] of target_turtle [Feature] of neighbor_turtle
[ if ?1 = ?2 [ set suma suma + 1] ]
)
report suma
]
end
Your code seems almost correct already, though the ask neighbor_turtle part isn't necessary; you're already using of to switch perspectives.
The error message you're getting seems to indicate that you need to somehow handle the case where the turtle's feature lists aren't the same length.
I'll assume you just want to ignore any trailing items in the longer of the two lists. Here's code that does that:
to-report overlap-between [target-turtle neighbor-turtle]
let features1 [feature] of target-turtle
let features2 [feature] of neighbor-turtle
ifelse length features1 > length features2
[ set features1 sublist features1 0 length features2 ]
[ if length features2 > length features1
[ set features2 sublist features2 0 length features1 ] ]
report sum (map [ifelse-value (?1 = ?2) [1] [0]]
features1 features2)
end
Note that it's idiomatic in NetLogo to name variables like-this not like_this.

Changing filtered values in a nested list

I have a nested list, in which each sublist is structured as follows: [[xcor ycor] weight].
Each tick I'd like to update the weight in a sample of these sublists.
I produce the sample (e.g. of size 2) from the nested list total using the Rnd extension (and very helpful answers/comments):
set total [ [[0 1] 1] [[2 3] 2] [[4 5] 3] [[6 7] 4] [[0 1] 1] ]
set sample rnd:weighted-n-of 2 total [ last ? ]
Then I update the weights in the sample (let's say multiplying them by 2) and map them to their respective [xcor ycor]-pair.
let newWeights (map [last ? * 2] sample)
let updatedSample (map list (map [first ?] sample) newWeights)
How can I then replace those entries in total, bearing in mind that it may hold duplicate entries?
This seems to be the perfect job for replace-item, but I don't know how to construct an appropriate index and then pass the respective value from updatedSample.
This is a great problem. The data structure you're using is known as an association list, or alist for short, where the keys are [xcor ycor] and the values are weights. Given your task, it's better to use the keys to look things up rather than indices. Thus, replace-item doesn't really help here. Instead, we can run map on total, using the values from updatedSample if they're there, and defaulting to the values in total. First, we need a convenience function to look things up in the alists. In lisp (a language which influenced NetLogo), this is called assoc. Here it is:
to-report assoc [ key alist ]
foreach alist [ if key = (first ?) [ report ? ] ]
report false
end
Notice that false is returned if alist doesn't contain the key. We want to use the entry returned by this function if it's not false, otherwise use something else. Thus, we need another helper function:
to-report value-or-else [ value default ]
report ifelse-value (value = false) [ default ] [ value ]
end
Finally, we can write a function that does the mapping:
to-report update-alist [ alist updated-entries ]
report map [ value-or-else (assoc first ? updated-entries) ? ] alist
end
Here's it in action:
observer> show update-alist [[[0 1] 1] [[2 3] 2] [[4 5] 3] [[6 7] 4] [[0 1] 1]] [[[0 1] 10] [[4 5] 45]]
observer: [[[0 1] 10] [[2 3] 2] [[4 5] 45] [[6 7] 4] [[0 1] 10]]
You would want to call it like update-alist total updatedSample.