1

我找到了一个为 LU 分解旋转方阵的代码,但我无法理解其中的一些。

def pivotize(m):
    """Creates the pivoting matrix for m."""
    n = len(m)
    ID = [[float(i == j) for i in xrange(n)] for j in xrange(n)]
    for j in xrange(n):
        row = max(xrange(j, n), key=lambda i: abs(m[i][j]))
        if j != row:
            ID[j], ID[row] = ID[row], ID[j]
    return ID

首先,ID 的行不就是单位矩阵吗?这样做有什么好处吗?

其次,我无法真正理解行的行。我知道 lambda 用于在文本中定义一个函数,一旦提供了 i 的值(并且 j 的值取决于 for 循环),它就会简单地返回 M_ij 的值,但是 i 是什么?

xrange 和 range 不相似吗?但它在这里返回了什么?

当与函数 max 结合时,会发生什么?我只是不知道正在比较的 max 函数中的内容是什么。

对不起,如果这个问题听起来很愚蠢。我对编程很陌生

4

2 回答 2

3

首先,ID 的行不就是单位矩阵吗?

是的。

其次,我真的无法理解行的行......

有关 max/key/lambda 交互的讨论,请参阅this。要回答“什么是i?”,它的 lambda 函数的参数i可以等效地是xfor foo。(为了清楚起见,分别产生abs(m[x][j])abs(m[foo][j]))。

xrange 和 range 不相似吗?

是的。在 Python 2xrange中,仅在需要时才返回一个延迟计算下一个值的序列对象。 请参阅此了解更多信息。当整个循环时,rangexrange产生相同的结果,但实现不同。

但它在这里返回了什么?

第 5xrange(n)行将返回从 0 到 (n-1)xrange(j, n)的整数值,而第 6 行将返回从 j 到 (n-1) 的整数值。

编辑

更多关于 lambda:

考虑如何获取给定的数字序列,并将它们中的每一个加倍。首先定义一个将数字翻倍x并返回该值的函数。然后将该函数映射到序列的每个元素。

# Traditional
def double(x): return x*2
print map(double, [1,2,3,4])         # [2, 4, 6, 8]

您也可以使用匿名 (lambda) 函数来做同样的事情:

# Lambda
print map(lambda i: i*2, [1,2,3,4])  # [2, 4, 6, 8]

请注意,一切都是一样的,除了double函数的定义消失了,调用中对函数的引用map被“内联”lambda函数替换。

编辑 2

当与函数 max 结合时,会发生什么?

这条线row = max(xrange(j, n), key=lambda i: abs(m[i][j]))可以分解如下:

  • xrange(j,n)生成从j(inclusive) 到n(exclusive) 的整数序列。
  • 然后,这些整数中的每一个都作为参数“传递”给 key 参数中的函数。换句话说,它们都被用作ilambda 函数中的 。lambda 函数“返回”i第 行和j第 列的绝对值。 [1]
  • 然后该max函数找到这些“lambda 输出”的最大值并将row其设置为相等。

这也可以写成列表理解的最大值:

row = max( [abs(m[i][j]) for i in xrange(j,n)] )

或者正如Dan D.在他的评论中指出的那样,写成生成器表达式(不创建中间列表),简单地说:

row = max( abs(m[i][j]) for i in xrange(j,n) )

笔记:

[1] 这里有一些假设,但行列是表达矩阵的标准方式。

于 2015-03-05T00:04:48.603 回答
2

xrange是一个 Python2 构造,用于处理range内存效率。在range实际创建一个列表之前,然后for循环会遍历它。xrange然而是一个生成器,这意味着它在被要求时一次吐出 1 个值,而不创建完整列表。

ID实际上是一个单位矩阵。你就在那儿。这是一个巧妙的技巧,可以将 boolean 转换为 float of value 1.0

然后代码片段遍历所有剩余的行,并在原始矩阵中找到该行的最大值row = max(xrange(j, n), key=lambda i: abs(m[i][j]))。请注意,这里有第二个不错的技巧,max可以对任何可迭代的对象进行操作,包括生成器。lambda该行中的关键字表示所谓的“匿名函数”。

更详细地说:匿名函数是未绑定到标识符的函数。您的代码段中的 Lambda 函数接受 1 个值,i并在矩阵位置返回一个绝对值m[i][j]。作为函数输入发送的值由生成器提供xrange(j, n)

max然后将 lambda 函数的返回值作为它实际比较的东西。例如,在 python3 中,无法比较 2 种不同的类型。即比较 string > int 产生:TypeError: unorderable types: str() > int()。但是,如果我们确定列表包含数字,只是格式不同,您可以执行以下操作:

>>> l = ["1", "2", 3, 4]
>>> max(l, key=lambda x: int(x))
4
>>> min(l, key=lambda x: int(x))
'1' #type 'str'

这只是表明,实际比较的值是您的key函数的返回值,但实际产生的值是您的原始输入值。

一旦找到行的最大值,它就会通过替换“旋转”单位矩阵中的ID[j], ID[row] = ID[row], ID[j]所有其他行,使其围绕它,以便只有最大值保留在对角线上。

这有助于防止在 LU 分解的下一步中除以太小的数字。

你得到的回报不是原始矩阵,旋转,而是一个1.0s 和0.0s 的矩阵,它是你的变换矩阵,乘以原始矩阵将产生旋转矩阵。

这似乎是一个写得很好的函数,可以节省内存并有助于提高 python 的性能。希望我做对了。

于 2015-03-05T00:08:07.643 回答