6

这是我的示例代码。它是高斯赛德尔(矩阵求解器)的迭代过程。本质上,当错误足够小时,它会退出 while 循环。

i=1
while (i>0):
    x_past = x_present

    j=0
    while(j<3):
        value=0
        k=0
        while(k<3):
            if(k!=j):
                if(i==1):
                    if(k>j):
                        value=value+0
                    else:
                        value=value+x_present[k]*eqn[j][k]    
                else:
                    value=value+x_present[k]*eqn[j][k]
            else:
                value=value+eqn[j][k]
            k=k+1
        x_present[j:j+1]=[value]
        j=j+1
    print "X_PAST"
    print x_past
    print "X_PRESENT"
    print x_present    
    if(error(x_past, x_present)<10**-2):
        break;
    i=i+1

我已经减少了代码,使其更易于管理。如果你不明白它在做什么,它对解决这个问题并不那么重要。

这是问题所在。每次

x_present[j:j+1]=[value]

运行时,x_past 等于 x_present。我不知道为什么会这样,因为我设置 x_past 等于 x_present 的唯一位置是在循环的顶部。如果我拿走

x_past=x_present

句子,x_past 永远不会等于 x_present。这使我认为这是导致问题的两种陈述的某种组合。

这是一个很大的问题,因为如果 x_past = x_present 每次错误 = 0 并且循环在第一次迭代后中断。代码确实有效,例如,如果我告诉代码运行 8 次迭代并且中断它给了我应该的答案。

在过去的 4 个小时里,我一直试图弄清楚这一点,但我完全被难住了。我使用 python 的时间不长,所以我在语法方面的故障排除技巧并不是那么好。任何帮助,将不胜感激!!

4

6 回答 6

31

是的,我认为这里的答案显示了您的问题。只是想澄清一点。

您正在引用一个列表,因此当列表更改时,对该列表的任何引用都将反映该更改。展示:

>>> x_present = [4,5,6]
>>>
>>> x_past = x_present
>>>
>>> x_past
[4, 5, 6]
>>>
>>> x_present.append(7)
>>>
>>> x_past
[4, 5, 6, 7]
>>>

如果你想要一份列表的副本,你必须这样做,listcopy = mylist[:]。(或者import copy;listcopy = copy.copy(mylist)

>>> x_past = x_present[:]
>>> x_past
[4, 5, 6, 7]
>>>
>>> x_present.append(8)
>>>
>>> x_past
[4, 5, 6, 7]
于 2008-11-05T08:13:16.343 回答
4

x_past 和 x_present 是什么?我不太了解 Python,但从 .NET/Java 的角度来看,如果它们引用了某些数据结构(地图或其他),那么让它们引用同一个对象(就像你在开始时所做的那样)将意味着通过一个变量所做的任何更改都将通过另一个变量可见。听起来您需要获取数据结构的副本,而不仅仅是进行引用分配。您正在使用的数据结构是否有任何可用的“克隆”功能?

正如我所说,我不太了解 Python,所以这可能是完全错误的......

于 2008-11-05T08:00:34.807 回答
3

正如其他人指出的那样,答案是替换:x_past = x_presentx_past = x_present[:]. 通常,您可以使用copy模块在 Python 中复制对象。

>>> import copy
>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = a
>>> a += 10, 11
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> c = copy.copy(a) # shallow copy
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> del a[3:]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

至少可以说,您的代码是 unpythonic。

它可以替换为类似以下代码的内容:

import copy
# assert(len(x_present) >= len(eqn))

first = True
while True:
    x_past = copy.copy(x_present) # copy

    for j, eqj in enumerate(eqn):
        x_present[j] = sum(x_present[k] * eqj[k] 
                           for k in range(j if first else len(eqj)) 
                           if k != j)
        x_present[j] += eqj[j] 

    print "X_PAST\n%s\nX_PRESENT\n%s" % (x_past, x_present)
    if allequal(x_past, x_present, tolerance=10**-2):
        break
    first = False

这是allequal()(使用绝对错误。在您的情况下它可能是一个好主意,也可能不是一个好主意(您可以改用相对错误)):

def allequal(x, y, tolerance):
    return (len(x) == len(y) and 
            all(-tolerance < (xx - yy) < tolerance
                for xx, yy in zip(x, y)))
于 2008-11-05T09:50:22.090 回答
1

在 Python 中,一切都是对象。所以语句 x_past = x_present 指向同一个引用。

于 2008-11-05T08:36:39.993 回答
0

看起来 x_present 好像是一个列表。我怀疑这意味着赋值 x_last = x_present 使 x_last 成为别名,即它们引用相同的变量。可能是这样吗?

于 2008-11-05T08:02:06.303 回答
0

尝试将x_past = x_present线路更改为x_past = [x for x in x_present],看看是否有帮助。

列表复制速记是我最喜欢的 python 功能,因为我可以做其他语言无法做到的单行:

greaterthan100 = [x for x in number if x > 100]

notinblacklist = [x for x in mylist if x not in blacklist]

firstchildofbigfamily = [x.child[0] for x in familylist if len(x.child) > 10]

于 2008-11-05T08:14:10.303 回答