Я хочу вычислить и сохранить две определенные величины, связанные со свойствами черепах, а именно подсчитать, сколько черепах соответствуют условию, и сумму конкретных атрибутов этих черепах. Этот конкретный атрибут принимает дискретные, целые, непоследовательные значения.
Минимальный пример кода модели будет выглядеть так:
globals [ N-x1 N-x2, N-x5 sum-A-x1 sum-A-x2 sum-A-x5 x-list ]
turtles-own [ condition1? A x ]
set x-list ( list 1 2 5 )
Учитывая, что в реальной модели x-list принимает 88 дискретных значений, я подумал, что использование цикла foreach будет подходящим способом справиться с этим. Обратите внимание, что количество черепах в реальной модели составляет около 75 тысяч, поэтому эффективность имеет значение.
Следуя комбинации предыдущих ответов (здесь и здесь), я придумал следующее решение:
foreach x-list
[ x ->
; Count turtles by x
let temp1 (word "set N-x" x " count turtles with [ condition1? = true and x = " x "]" )
run temp1
; Calculate sum of A by x
let temp2 (word "set sum-A-x" x " sum [ A ] of turtles with [ condition1? = true and x = " x "]" )
; Capture errors due to empty list in calculating the sum
carefully [ run temp2 ]
[ let temp3 (word "set sum-A-x" x " 0" )
run temp3
]
]
Хотя это и работает, каждый прогон модели существенно замедлялся. Простое (но все же грубое) решение, которое, как я думал, поможет ускорить код, — это сначала определить набор агентов черепахи, на котором будут выполняться последующие команды (подсчет и суммирование). Поскольку я не смог найти способ использовать let внутри цикла foreach для этого, я решил вручную определить все вручную (для каждого из 88 значений x):
; Define needed agentsets
let turtles-x1 with [ condition1? = true and x = 1 ]
let turtles-x2 with [ condition1? = true and x = 2 ]
let turtles-x5 with [ condition1? = true and x = 5 ]
; Count turtles meeting condition1
set N-x1 count turtles-x1
set N-x2 count turtles-x2
set N-x5 count turtles-x5
; Sum A over turtles meeting condition1
if N-x1 > 0 [ set sum-A-x1 sum [ A ] of turtles-x1 ]
if N-x2 > 0 [ set sum-A-x2 sum [ A ] of turtles-x2 ]
if N-x5 > 0 [ set sum-A-x5 sum [ A ] of turtles-x5 ]
Казалось, это немного улучшило производительность. Может ли кто-нибудь придумать более эффективный (то есть более разумный) способ сделать то же самое? Например. используя map, о котором я не могу понять, или расширение table?
Обновлено: хотя ответы по-прежнему приветствуются, я нашел способ решить проблему, используя расширение table и map. Оставлю здесь, на случай, если кто-нибудь наткнется на подобный случай.
Спасибо @Jasper, готово! (И приносим извинения за незнание правил/норм сообщества.. :-))





Следуя ответам, найденным здесь и здесь, гораздо более эффективное решение:
globals [ x-keys x-N turtle-list turtle-A ]
; Store table of relevant turtles and their x's (to preserve order)
let temp-table table:group-agents turtles with [ condition1? = true ] [ x ]
; Relevant turtles' Xs (in the order inserted)
set x-keys table:keys temp-table
; Counts of relevant turtles per x (in the order inserted)
set x-N map count table:values temp-table
; Relevant turtles in the order inserted (in an agentset list)
set turtle-list table:values temp-table
; Calculate sum of A per x
set turtle-A map [ y -> precision ( sum [ A ] of y ) 3 ] turtle-list
Это решает многие проблемы, такие как предварительное определение каждой переменной, выполнение нескольких if для проверки, заполнен ли x (т. е. N > 0) для запуска суммы, и сохранение ненужной информации (например, установка суммы случаев вручную с N = 0, до нуля). Это значительно повысило скорость и вдвое уменьшило размер генерируемого вывода (в эксперименте BehaviorSpace).
Я рад, что вы нашли решение, которое вам подходит! Оставить ответ на свой вопрос в SO можно, и это приветствуется. Вам также следует пометить его как принятый, чтобы любой, кто его найдет, знал, что это решило проблему.