嵌套循环 - 保持迭代次数不变

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

根据@mypetition的要求,我正在编辑我的问题,尽管我认为这里的天文学细节并不重要。我有一个表格的文件:

   a          e        q          Q          i        lasc       aper      M          H      dist   comment     i_f      i_h      i_free
45.23710   0.1394   38.93105   51.54315    5.0300    19.9336   286.2554   164.9683   8.41   51.3773   warm     0.000    62.000     4.796
46.78620   0.1404   40.21742   53.35498    3.1061   148.9657   192.3009   337.5967   7.37   40.8789   cold     0.000    42.000     2.473
45.79450   0.1230   40.16178   51.42722    8.0695   104.6470   348.5004    32.9457   8.45   41.3089   warm     0.000    47.000     6.451
42.95280   0.0145   42.32998   43.57562    2.9273   126.3988   262.8777   163.4198   7.36   43.5518   cold     0.000   161.000     2.186

总共有1.6e6线。这些是轨道元素。我需要计算每对轨道之间的最小轨道交点距离(MOID),例如第1行第2行,第1行第3行,依此类推,直到我到达文件末尾。然后,我从第二行开始,然后转到文件的末尾。然后从第三行开始,agin到文件的末尾等。因为我有1.6e6轨道,那将是~1e12轨道对。

我不想在1个cpu上加载所有这些1e12计算并永远等待,所以我打算使用集群并启动多个串行作业。

我需要遍历1.6e6元素,在那里我从第一个元素开始并转到文件的末尾,然后从第二个元素开始并转到文件的末尾等,直到我最后开始使用T-1并转到T。这将导致10^12迭代,我计划将它们分成多个作业,每个作业执行C=10^7计算,因此我可以在计算机集群上运行它们。 我想出了以下嵌套循环:

for i in range( M, N)
  for j in range( i+1, T)

在哪里M=1并根据我将拥有的工作数量而变化。 T=1.6e6是常量(迭代的行数)。我想找到索引N,这样操作的总数就是C=10^7。以下是我解决问题的方法:[T-(N+1) + T-(M+1)]*(M-N+1)/2=C - 因为操作的数量只是上面算术系列的总和。所以,我解决了二次方程式,得到了根。这是python代码:

import numpy as np
import math

C=1.0e7  # How many calculations per job do you want?
T=1.6e6  # How many orbits do you have?
M=1      # what is the starting index of outer loop?
#    N = end index of outer loop (this is to be calculated!)
P=1
l=0
with open('indx.txt','w') as f:

   while P<T:
      l=l+1
      K=np.roots([-1,2*T,M**2-2*T*(M-1)-2*C])
      N=int(round(K[1]))

      f.write("%s %s\n" % (P,P+N))
      M=K[1]+1
      P=P+N+1

然而,保持上述解决方案,更新M = M + N,我注意到不满足条件C = 10 ^ 7。这是前几个指数的列表。

M N

1 7
8 21
22 41
42 67
68 99
100 138
139 183
184 234
235 291
 ....
 ....
1583930 1588385
1588386 1592847
1592848 1597316
1597317 1601791

但如果你在最后一个之前看一对,那么i=1592848 - 1597316j=i+1, T的循环将产生比C=10^7更多的计算,即大致(2685 + 7153)* 4468 / 2~2.2e7。

关于如何解决这个问题的任何想法,保持C = 1e7不变,这将提供我需要运行的作业数量(具有相似的运行时间)以迭代超过1.6e6线。

希望根据@mypetition标准,这个解释已经足够了,我希望能解决这个问题。

我们将非常感谢您的帮助!

python while-loop indices
1个回答
0
投票

我不知道每个工作的性质是否可以适用于不同类型的分裂但是如果它们这样做,你可以尝试使用高斯用来提出的相同技巧Σ1..n= n(n + 1)/ 2

诀窍是将序列与它的反转副本对齐:

1  2  3  4  5  6  7  8  
8  7  6  5  4  3  2  1 
-- -- -- -- -- -- -- --
9  9  9  9  9  9  9  9  = 8 * 9 is twice the sum so (8*9)/2 = ∑1..8 = 36

基于此,如果你将这对系列分开到中间,你将获得4对运行,它们将处理相同数量的元素:

1  2  3  4    
8  7  6  5  
-- -- -- -- 
9  9  9  9  

你可以在4个工作中分开8次。每个作业将处理n + 1(9)个元素并计算具有互补元素数量的两个运行

Job 1 would do run 8..8 and run 1..8 (length 1 and 8)
Job 2 would do run 7..8 and run 2..8 
Job 3 would do run 6..8 and run 3..8
Job 4 would do run 7..8 and run 4..8

更笼统地说:

(N + 1)/ 2的作业i运行(N-i + 1)... N和i..N

如果单个运行不能进一步并行化,这应该给你最佳的传播(实际上是总处理时间的平方根)

在Python(伪代码):

size = len(array) 
for index in range((size+1)//2):
    launchJob(array, run1Start=index, run2Start=size-index-1)

注意:如果您没有使用基于零的索引,则可能需要调整起点。

注意2:如果你没有自己处理最后一个元素(即N..N被排除在外),你的一个作业将有N个要处理的元素而不是N + 1,你必须为那个做一个例外

添加更多作业不会显着改善总处理时间,但如果您想要更少的并行作业,您仍然可以通过分组对保持它们相当。

例如2个职位:[1,8,2,7]和[3,6,4,5] =每个职位18个

理想情况下,您的工作数量应该是成对数量的分配器。如果没有,通过在其他作业上均匀分布额外的对(或运行),您仍将获得相对平衡的处理时间。如果选择扩展运行,请选择对列表中间的那些(因为它们将具有彼此更接近的单独处理时间)。

© www.soinside.com 2019 - 2024. All rights reserved.