将海龟变量映射到补丁

问题描述 投票:0回答:3

我为每只海龟创建了一个变量

utilities
(分配给补丁(学校)的实用程序),其中包含从
school-utility
(记者)派生的 30 个值,每个值对应一个补丁(学校)。每只海龟在该变量上都有 30 个值。然后我为每只海龟创建了累积总和。

to utility
  set utilities [ school-utility ] of patches with [ schoolachievement_2 > 0 ]
  set  cumul sum utilities
  let temp utilities
  set  school-utility_1  map [ i -> i / cumul ] temp
  set school-utility_1  sort school-utility_1


  let cum-sum []
  let sum-so-far 0
  let index 0
  foreach school-utility_1 [
    let next-sum sum-so-far + item index school-utility_1
    set cum-sum lput next-sum cum-sum
    set sum-so-far next-sum
    set index index + 1
  ]
  set cum-utility_1 cum-sum

我试图让海龟选择补丁(学校),以最小化

random-number 0 + random-float 1
cum-utility_1
之间的差异。问题是
cum-utility_1
是一个海龟变量。

我已经尝试过了

set targets patches with <....>
    let min-patch  min-one-of targets [abs (random-number - [ cum-utility_1] of myself)]

但我收到消息

- expected input to be a number but got the list...

我也尝试过

set targets patches with <....>
    let min-patch  min-one-of targets [abs (random-number - cum-utility_1)]

得到

this code can't be run by a patch, only a turtle...
我怀疑问题是 Netlogo 不知道如何将
cum-utility_1
的不同值映射到每个补丁(学校)。

variables netlogo
3个回答
3
投票

对于每只需要将实用程序链接到补丁的海龟来说,这是一种方法。它使用列表的列表,其中每个子列表的第一个元素是补丁(学校),第二个元素是与该补丁相关的一些值。列表的列表有点棘手,但一旦你习惯了它们,就不那么糟糕了。请注意,我的

school-utility
报告器只是说明性的,但它确实包含来自补丁和乌龟的变量,正如我收集到的那样。另请注意,
random-number 0 + random-float 1
不是有效的语法,因此我将其解释为
random-number
是您要从中减去每个
cum-utility
的随机数。最后,如果不将其嵌入到更大的模型中,我无法测试此代码,因此可能存在我尚未发现的语法错误。

;school-utility should return a list of lists, of the form [[patch value] [patch value] ...]
;For instance:
to-report school-utility
  report list self (school-achievement_2 * [some-variable] of myself)
end

;Then,

to utility
  set utilities [ school-utility ] of patches with [ schoolachievement_2 > 0 ]
  set  cumul sum map [i -> last i] utilities
  set  school-utility_1  map [ i -> list (first i) (last i / cumul) ] utilities
  set school-utility_1  sort-by [[i j] -> last i < last j] school-utility_1

;Now we have the patches sorted by their utilities, with the first item in each
;sublist being the patch and the second (last) being the utility.

  let cum-sum []
  let sum-so-far 0
  foreach school-utility_1 [i ->
    let next-sum sum-so-far + last i
;for a simple list without patch links
    set cum-sum lput next-sum cum-sum
;for a list with patch links, which is what you will want below
    set cum-sum lput list first i cum-sum
    set sum-so-far next-sum
  ]
  set cum-utility_1 cum-sum
;I think that last cum-utility_1 = 1.0?
  
  let random-number random-float 1
  let possible-targets map [i -> list first i abs (random-number - last i)]
;Now we want to find the sublist in possible targets with the minimum value for its
;second (last) element. target will be the first item in the first
;sublist of the sorted possible-targets.
  set target first first sort-by [[i j] -> last i < last j] possible-targets

end

我认为使用链接可能不像@LeirsW 和我最初想象的那么糟糕。我可能会玩一下。


2
投票

这是使用链接解决问题的另一种方法。每个学生在搜索过程中都会创建指向潜在学校的链接,然后将其删除,而不是永久链接。这会产生一些开销,但在任何给定时间的链接数量仍然很小。而且,由于学生和每个潜在学校之间存在单一链接,因此该链接可以保存特定于每个学生/学校对的那些变量。然而,有一个问题。 NetLogo 不允许海龟和斑块之间存在链接,因此我们不得不将学校设为一种海龟,然后将其放置在斑块上。这实际上是一种更好的方法,因为补丁是一个位置,而学校是一个将位置作为一个实体,但只是其属性之一。既然学校是海龟的一个品种,那么让学生拥有自己的品种也是有意义的。

同样,如果没有完整的模型,我无法测试其准确性或速度。

breed [schools school]
breed [students student]
links-own [school-utility_1 cum-utility_1 target-value]
students-own [some-variable target]
schools-own [school-achievement_2]

to-report school-utility 
  ; Since these are directed links created by
  ; students, they run from student (end1) to school (end2).
  report ([school-achievement_2] of end2 * [some-variable] of end1)
end

to utility ; this is run by turtles (students)
  ; create links to possible targets (schools) and have each link 
  ; determine the utility of that school.
  let possible-targets schools with [school-achievement_2 > 0]
  create-links-to possible-targets [
    set school-utility_1 school-utility 
  ]
  
  ; sum the utilties of all the possible schools
  let cumul sum [school-utility_1] of my-out-links
  ; calculate the school utilities relative to the total
  ask my-out-links [set school-utility_1 school-utility_1 / cumul]
  
  ; now sort the links by school-utility_1.  
  ; this gives us a list of links to the schools.
  let sorted-links sort-on [school-utility_1] my-out-links
  ; and build the cum-utility_1 values
  let sum-so-far 0
  foreach sorted-links [i ->
    let next-sum sum-so-far + [school-utility_1] of i
    ask i [set cum-utility_1 next-sum]
    set sum-so-far next-sum
  ]
  
  ; now find the target.
  ; We want to find the link, and thus the school, with the minimum calculated value.
  let random-number random-float 1
  ask my-out-links [
    set target-value abs (random-number - cum-utility_1)
  ]
  set target [end2] of min-one-of my-out-links [target-value]
  
  ; finally, clean up
  ask my-out-links [ die ]
  
end

0
投票

@Charles,@LeirsW,非常感谢您的建议。使用您建议的列表方法代码列表,我现在拥有以下内容。代码没有给出错误,海龟确实按照预期移动到补丁,但我仍在尝试了解代码是否满足我的需要。 谢谢你,尼克

to-report school-utility
  report  ( (schoolachievement_2)  * [ some-variable ] of myself )
end

to utility
  let patches-with-utilities patches with [schoolachievement_2 > 0]
  let cumul 0
  let utilities []
  foreach (list patches-with-utilities) [p ->
    ask p [
      let util school-utility
      set cumul cumul + util
      set utilities lput (list p util) utilities
    ]
  ]
  set school-utility_1 map [i -> list (first i) (last i / cumul)] utilities

  let cum-sum []
  let sum-so-far 0
  foreach school-utility_1 [i ->
    let next-sum sum-so-far + last i
    ; for a list with patch links, which is what you will want below
    set cum-sum lput cum-sum (list first i)
    set sum-so-far next-sum
  ]
  set cum-utility_1 cum-sum
;last cum-utility_1 = 1.0

to test

  let random-number random-float 1.00001
  let possible-targets map [i -> list (first i) abs (random-number - last i)] school-utility_1

;Now we want to find the sublist in possible targets with the minimum value for its
;second (last) element.  
  let target nobody
  let lowest 100
  foreach possible-targets [i ->
   if last i < lowest [
      set lowest last i
      set target first i
    ]
  ]
  if target != nobody [
      move-to one-of target
      set enrolled? TRUE
   
  ]
© www.soinside.com 2019 - 2024. All rights reserved.