英文:
How to speed up a while loop with many list filtering procedures each of 200 turtles runs on 2600 patches
问题
To improve the performance of your model and make the decisionforprofit
loop faster, you can consider the following optimizations:
-
Precompute Patch Lists: Instead of creating the list of available patches and their characteristics within the loop for each turtle, you can precompute this list once before the loop starts and update it only when necessary (e.g., when patches become unavailable due to ownership changes). This way, you avoid recomputing the same information multiple times.
-
Parallel Processing: Depending on your simulation environment, you may be able to take advantage of parallel processing to distribute the workload among multiple cores or processors. This can significantly speed up the execution of your model, especially if you have a large number of turtles and patches.
-
Data Structures: Consider using more efficient data structures to store and manipulate your data. For example, use dictionaries or arrays to store patch information so that you can quickly access patches based on their characteristics without iterating through the entire list.
-
Reduce Redundant Checks: Look for opportunities to reduce redundant checks within your code. For example, if a patch's suitability doesn't change within a tick, you don't need to recheck it for every turtle. You can store suitability values and update them when necessary.
-
Profile Your Code: Use profiling tools to identify performance bottlenecks in your code. Profiling will help you pinpoint which parts of your code consume the most time and need optimization.
-
Limit Unnecessary Operations: Analyze your code to identify any unnecessary operations or conditions that can be skipped to save computation time. For instance, if a turtle has insufficient investable money for a particular land use change, you can skip processing that option.
-
Batch Processing: Instead of processing each turtle one at a time, consider batch processing multiple turtles at once. This can reduce overhead and improve efficiency.
-
Use Agentsets: Agentsets can help you organize and manipulate turtles and patches efficiently. Use them to filter and select agents based on specific criteria.
-
Simplify Decision Logic: If possible, simplify the decision-making logic within your loop. Complex conditional statements can slow down execution. Try to minimize the number of conditions that need to be checked.
-
Optimize Patch Queries: Ensure that patch queries, such as
any?
andwith
, are as efficient as possible. Avoid unnecessary nested queries and use agentsets when appropriate. -
Reduce the Number of Turtles: If your model's performance remains an issue, consider reducing the number of turtles in your simulation. This can lead to a significant improvement in execution speed.
Implementing these optimizations should help you make your model run faster and more efficiently. Remember to profile your code and measure the impact of each optimization to ensure you're making effective improvements.
英文:
I am working in a decision-making ABM, my turtles must identify the best land use change strategy based on the characteristics and availability of patches suitable to make the best decisions. However the code I have takes a lot of time to process the decision of the agent.
this is a list of potential land use changes :
set landuselist [
;; in the list
;; +------------------------ landusechange
;; | +------------------ cost
;; | | +------------- expectedprofit
;; | | | +---------- maize
;; | | | | +----- expectedprofit(formodification)
;; | | | | |
[ "MEA1" 200 450 6 450 ] ;; maintenance of mechanized agriculture in patches with high suitability for mechanized agriculture
[ "TRA1" 50 350 3 350 ] ;; maintenance of traditional agriculture to traditional agriculture in patches with high suitability for traditional agriculture
[ "CAT1" 100 350 0 350 ] ;; maintenance of cattle ranching in any suitability except for null
[ "AGF1" 50 600 1 600 ] ;; Maintenance of agroforestry with an age over or equal to 6 year on suitability over null for agroforestry
[ "MEA2" 200 450 6 450 ] ;; conversion of forest to mechanized agriculture in patches with high suitability for mechanized agriculture
[ "TRA2" 100 300 3 300 ] ;; conversion of forest to traditional agriculture in patches with high suitability for traditional agriculture
[ "CAT2" 600 300 0 300 ] ;; change from forest to cattle ranching in any patch with suitability over null suitability
[ "AGF2" 50 50 1 50 ] ;; Maintenance of agroforestry with an age below 6 year on suitability over null for agroforestry
[ "MEA3" 200 450 6 450 ] ;; conversion of land uses different than forest and mechanized agriculture into mechanized agriculture in patches with high suitability for mechanized agriculture
[ "TRA3" 50 200 3 200 ] ;; conversion of land uses different to forest or traditional agriculture to traditional agriculture in patches with high suitability for traditional agriculture
[ "CAT3" 600 300 0 300 ] ;; change of land uses diferent to forest and cattle ranching to cattle ranching in any level of suitability
[ "AGF3" 350 50 1 50 ] ;; change from land uses different from forest and agroforestry to agroforestry in any suitability level exepct for null for agroforestry
[ "MEA4" 250 300 5 300 ] ;; maintenance of mechanized agriculture in patches with medium suitability for mechanized agriculture
[ "TRA4" 50 200 2 200 ] ;; maintenance of traditional agriculture to traditional agriculture in patches with medium suitability for traditional agriculture
[ "MEA5" 250 300 5 300 ] ;; conversion of forest to mechanized agriculture in patches with medium suitability for mechanized agriculture
[ "TRA5" 100 200 2 200 ] ;; conversion of forest to traditional agriculture in patches with medium suitability for traditional agriculture
[ "MEA6" 250 300 5 300 ] ;; conversion of land uses different than forest and mechanized agriculture into mechanized agriculture in patches with medium suitability for mechanized agriculture
[ "TRA6" 50 150 2 150 ] ;; conversion of land uses different to forest or traditional agriculture to traditional agriculture in patches with medium suitability for traditional agriculture
[ "MEA7" 250 250 4 250 ] ;; maintenance of mechanized agriculture in patches with low suitability for mechanized agriculture
[ "TRA7" 50 150 1 150 ] ;; maintenance of traditional agriculture on patches with traditional agriculture in patches with low suitability for traditional agriculture
[ "MEA8" 250 250 4 250 ] ;; conversion of forest to mechanized agriculture in patches with low suitability for mechanized agriculture
[ "TRA8" 100 100 1 100 ] ;; conversion of forest to traditional agriculture in patches with low suitability for traditional agriculture
[ "MEA9" 250 250 4 250 ] ;; conversion of land uses different than forest and mechanized agriculture into mechanized agriculture in patches with low suitability for mechanized agriculture
[ "TRA9" 50 100 1 100 ] ;; conversion of land uses different to forest or traditional agriculture to traditional agriculture in patches with low suitability for traditional agriculture
]
this is my while loop :
to decideforprofit ;;;; procedure to create the decision model based.
;;;; It is a secondary process after maize self-consumption
set ownedpatcheslist [] ;; used to create a list of patches owned by each agent
while [investablemoney >= 50] [ ;; defined as the smallest cost to do a land use change
create-patch-types ;; create a list of available patches in its respective procedure to have only the available patches and their potential benefit in land use change
set alternatives filter [parches -> member? (item 0 parches) patch-types] landuselist ;;; to work with a list for each turtle that we can modify, it filters the global list based on the lo
create-patch-types list
let landuselist1 filter [lista -> item 1 lista <= investablemoney] alternatives;;; filter based on the budget of each turtle
let landuselist2 sort-with [ l -> item 2 l ] landuselist1 ;;; sort the alternatives of each turtle to find the most profitable one
ifelse empty? landuselist2 [ ;;; when there are not more patches then to continue the procedure as normal for the next turtle
;handle the case where there are no suitable patches
;show "NO AVAILABLE PATCHES"
] [;;; if it is not empty then
let highest-value first landuselist2 ;;; chose the most profitable land use change from the nested list
let value item 0 highest-value ;;; define the land use change "MEA1", "MEA2"...
set chosevalue value ;;; the turtle receive the order
let costs item 1 highest-value ;;; extract the cost of the decision from the list
let income item 2 highest-value ;;; extract the income of the decision form the list
set investablemoney (investablemoney - costs);; discount the cost to the variable investablemoney of turtles
set savings (savings + income) ;;; add the income of the decision to the savings variable
applydecisions;;; procedure that execute the order in chosevalue
]
if empty? landuselist2 or investablemoney < 50 [
;exit the while loop if there are no suitable alternatives or there is not enough investable money
;show "I am stopping#"
stop
]
]
;;; end of the while
end
;;;decideforprofit()
this is the procedure to create a list of available patches and land use change options :
to create-patch-types ;; this creates a list of patches
;; based on the patch suitability
;; current land use and ownership
set patch-types []
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; choices for traditional agriculture
if any? patches with [(land-use = "TRA") and (OwnerId = [who] of myself) and (TRAsuitability = 3) and (inuse = 0)] [set patch-types lput "TRA1" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (TRAsuitability = 3) and (inuse = 0)] [set patch-types lput "TRA2" patch-types]
if any? patches with [member? land-use ["MEA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (TRAsuitability = 3) and (inuse = 0)] [set patch-types lput "TRA3" patch-types]
if any? patches with [(land-use = "TRA") and (OwnerId = [who] of myself) and (TRAsuitability = 2) and (inuse = 0)] [set patch-types lput "TRA4" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (TRAsuitability = 2) and (inuse = 0)] [set patch-types lput "TRA5" patch-types]
if any? patches with [member? land-use ["MEA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (TRAsuitability = 2) and (inuse = 0)] [set patch-types lput "TRA6" patch-types]
if any? patches with [(land-use = "TRA") and (OwnerId = [who] of myself) and (TRAsuitability = 1) and (inuse = 0)] [set patch-types lput "TRA7" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (TRAsuitability = 1) and (inuse = 0)] [set patch-types lput "TRA8" patch-types]
if any? patches with [member? land-use ["MEA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (TRAsuitability = 1) and (inuse = 0)] [set patch-types lput "TR9" patch-types]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; choices for mechanized agriculture
if any? patches with [(land-use = "MEA") and (OwnerId = [who] of myself) and (MEAsuitability = 3) and (inuse = 0)] [set patch-types lput "MEA1" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (MEAsuitability = 3) and (inuse = 0)] [set patch-types lput "MEA2" patch-types]
if any? patches with [member? land-use ["TRA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (MEAsuitability = 3) and (inuse = 0)] [set patch-types lput "MEA3" patch-types]
if any? patches with [(land-use = "MEA") and (OwnerId = [who] of myself) and (MEAsuitability = 2) and (inuse = 0)] [set patch-types lput "MEA4" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (MEAsuitability = 2) and (inuse = 0)] [set patch-types lput "MEA5" patch-types]
if any? patches with [member? land-use ["TRA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (MEAsuitability = 2) and (inuse = 0)] [set patch-types lput "MEA6" patch-types]
if any? patches with [(land-use = "MEA") and (OwnerId = [who] of myself) and (MEAsuitability = 3) and (inuse = 0)] [set patch-types lput "MEA7" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (MEAsuitability = 1) and (inuse = 0)] [set patch-types lput "MEA8" patch-types]
if any? patches with [member? land-use ["TRA" "CAT" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (MEAsuitability = 1) and (inuse = 0)] [set patch-types lput "MEA9" patch-types]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; choices for cattle ranching
if any? patches with [(land-use = "CAT") and (OwnerId = [who] of myself) and (CATsuitability > 0) and (inuse = 0)] [set patch-types lput "CAT1" patch-types]
if any? patches with [(land-use = "TFM") and (OwnerId = 999) and (CATsuitability > 0) and (inuse = 0)] [set patch-types lput "CAT2" patch-types]
if any? patches with [member? land-use ["MEA" "TRA" "AGF"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (CATsuitability > 0) and (inuse = 0)] [set patch-types lput "CAT3" patch-types]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; choices for agroforestry
if any? patches with [(land-use = "AGF") and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0) and (age >= 6)] and any? patches with [(land-use = "AGF") and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0) and (age >= 6)] [set patch-types lput "AGF1" patch-types]
if any? patches with [(land-use = "AGF") and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0) and (age < 6)] and any? patches with [(land-use = "AGF") and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0) and (age < 6)] [set patch-types lput "AGF2" patch-types]
if any? patches with [member? land-use ["MEA" "CAT" "TRA"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0)] and any? patches with [member? land-use ["MEA" "CAT" "TRA"] or (land-use = "FAL" and age > 4) and (OwnerId = [who] of myself) and (AGFsuitability > 0) and (inuse = 0)] [set patch-types lput "AGF3" patch-types]
end
;;;create-patch-types()
There is another procedure that executes on each land use change option.<br>
this is an example :
to applydecisions
if (chosevalue = "TRA1") [move-to one-of patches with [land-use = "TRA" and (OwnerId = [who] of myself) and TRAsuitability = 3 and inuse = 0]
ask patch-here [set land-use "TRA" set OwnerId [who] of myself set breedowner [breed] of myself set inuse 1 ]
set ownedpatcheslist lput patch-here ownedpatcheslist ]
if (chosevalue = "TRA2") [move-to one-of patches with [land-use = "TFM" and OwnerId = 999 and TRAsuitability = 3 and inuse = 0]
ask patch-here [set land-use "TRA" set OwnerId [who] of myself set breedowner [breed] of myself set age 1 set inuse 1]
set ownedpatcheslist lput patch-here ownedpatcheslist]
end
;;;applydecisions()
How to make my model faster? What I have identified is that it takes long time for each turtle to run the while procedure because they must build a different list every time in the loop and per tick.
I would like to identify the best way to make the decisionforprofit
loop faster in order that my turtles consider the money they have and the available patches (not owned by other turtles or already owned by the same turtle) to make land use change: currently I have 200 turtles and 2600 patches varying in three levels of suitability for each land use type.
答案1
得分: 1
考虑编程中的DRY原则。
不要重复自己。
如果您可以在代码中找到重复的模式,您将找到减少执行指令数量的机会。
考虑owner-id = [who] of myself
首先,[who] of myself
被多次运行。我们可以考虑将其存储在一个本地变量中,然后在查询中使用它。但是,在这种情况下,将myself
分配给owner-id是不好的NetLogo风格。在这种情况下,只需在乌龟声明贴片时将myself
分配给owner-id。
ask patches with [ patch-selection-criteria ]
[ set owner-id myself ]
接下来,测试owner-id = myself
再次运行此测试会对所有贴片多次运行。这是数千次不必要的测试!让我们将查询的一部分存储在一个本地变量中。
let my-patches patches with [ owner-id = myself ]
if any? my-patches with [ test1 ] [ action1 ]
if any? my-patches with [ test2 ] [ action2 ]
;; ... and so on
我们现在已经删除了数千次的测试。您可能会看到显着的性能改进。
其他可能的改进:
- 看看是否可以避免测试
member?
。 - 看看是否可以使用数值代码而不是字符串。
- 看看是否可以避免重建不变的事物。
- 看看是否可以安排数据,以便不需要过滤。
- 看看是否可以将搜索转化为查找。
这是一个开始。希望有人会添加更多的想法。
我现在没有时间详细说明这个建议,但您可以考虑使用其他乌龟作为对象来保存和查询您的土地使用属性。
英文:
Consider the DRY principle of programming.
Don't Repeat Yourself.
If you can find repeating patterns in your code, you will find opportunities to reduce the number of instructions being executed.
Consider owner-id = [who] of myself
First, [who] of myself
is run many, many times. We might consider storing that in a local variable, then use that in the queries. But, using WHO as an ID is poor NetLogo style. In this case, just assign myself
to the owner-id when the turtle claims the patch.
ask patches with [ patch-selection-criteria ]
[ set owner-id myself ]
Next, the test 'owner-id = myself`
Again this test is run against all the patches many times. That's thousands of unnecessary tests! Let's store that part of the query in a local variable.
let my-patches patches with [ owner-id = myself ]
if any? my-patches with [ test1 ] [ action1 ]
if any? my-patches with [ test2 ] [ action2 ]
;; ... and so on
We have now removed thousands and thousands of tests. You likely will see significant performance improvement.
Other possible improvements:
- See if you can avoid testing
member?
. - See if you can use numeric codes instead of strings.
- See if you can avoid rebuilding thing that don't change
- See if you can arrange your data so filtering isn't needed
- See if you can transform searches into look-ups
That's a start. Hopefully someone will add more to ideas.
I don't have time to expand on this suggestion right now, but you may consider using other turtles as objects to hold and query your land use properties.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论