分配变量 = 自己创建一个副本。需要它作为参考(指针)
Assigning variable = self creating a copy. Need it to be a reference (pointer)
我正在为我的分配创建矩阵 class,通常如果我将变量分配为 x = self
,x 是对 self
的引用,因此所有操作到位。我有一个减少矩阵的函数,作为可选参数,我添加了 inplace=False
这样:
if inplace:
self = A
else:
A = self.copy()
现在通常我这样做的时候,如果我做A += B
这样的操作,self
就会被修改。但是我在运行A.reduce(inplace=True)
的时候,A
是没有修改的。我在下面包含了完整的 class,希望有人能告诉我为什么操作没有到位。提前致谢。
import numpy as np
class matrix:
def __init__(self, A):
self.value = np.array(A, dtype=np.float)
self.indices = np.arange(self.value.shape[0])
self.shape = self.value.shape
def swap_rows(self, r1, r2):
ind = np.arange(self.value.shape[0])
swap = (r1, r2)
ind[swap[0]] = swap[1]
ind[swap[1]] = swap[0]
temp_ind = self.indices[swap[0]]
self.indices[swap[0]] = self.indices[swap[1]]
self.indices[swap[1]] = temp_ind
self.value = self.value[ind]
def add_rows(self, operations):
# operations = [(c, row1, row2)]
# where operation will be:
# c * row1 + row2 -> row2
for c, row1, row2 in operations:
self.value[row2] += c * self.value[row1]
# ... #
def reduce(self, b_ = None, swap=True, normalize=True, return_steps=False, inplace=False, debug=False):
if inplace:
A = self
else:
A = self.copy()
if b_:
b = b_.copy()
if len(b.shape) == 1:
b.reshape((-1, 1), inplace=True)
if return_steps:
steps = []
# Normalize
if normalize:
A_max = A.row_max()
A /= A_max
if debug:
print("A after normalization:")
print(A)
print("")
if return_steps:
steps.append([('normalize', A_max)])
if b_:
b /= A_max
m, n = A.shape
for col in range(n-1):
# Swap
if swap:
# Check for max value
max_ind = np.argmax(np.abs(A[:, col]))
# Check if max is zero
if np.abs(A[max_ind, col]) < 1e-30:
print('Matrix is singular')
if b_:
return A, b
else:
return A
# Swap if necessary
if max_ind > col:
A.swap_rows(col, max_ind)
if return_steps:
steps.append([('swap', col, max_ind)])
if b_:
b.swap_rows(col, max_ind)
# Get constants
cs = -A[col+1:, col] / A[col, col]
operations = [(c, col, i+col+1) for i, c in enumerate(cs)]
if return_steps:
steps.append(operations)
A.add_rows(operations)
if b_:
b.add_rows(operations)
if debug:
print("A after row operations:")
print(A)
print("")
return_vals = np.array([A, None, None])
if b_:
return_vals[1] = b
if return_steps:
return_vals[2] = steps
if inplace:
return_vals = return_vals[1:]
if return_vals.any():
return tuple(return_vals[return_vals != None])
# ... #
def row_max(self):
return np.array([self[row, i] for row, i in enumerate(np.argmax(np.abs(self.value), axis=1))]).reshape(-1, 1)
# ... #
def copy(self):
return matrix(np.copy(self.value))
def T(self):
return matrix(self.value.T)
def inverse(self):
return matrix(np.linalg.inv(self.value))
def flip(self, axis=None, inplace=False):
if inplace:
self.value = np.flip(self.value, axis=axis)
else:
return matrix(np.flip(self.value, axis=axis))
def reshape(self, shape, inplace=False):
if inplace:
self.value = self.value.reshape(*shape)
else:
return matrix(self.value.reshape(*shape))
def __add__(self, x):
if isinstance(x, matrix):
return matrix(self.value + x.value)
else:
return matrix(self.value + x)
def __sub__(self, x):
if isinstance(x, matrix):
return matrix(self.value - x.value)
else:
return matrix(self.value - x)
def __mul__(self, x):
if isinstance(x, matrix):
return matrix(self.value * x.value)
else:
return matrix(self.value * x)
def __truediv__(self, x):
if isinstance(x, matrix):
return matrix(self.value / x.value)
else:
return matrix(self.value / x)
# ... #
def __matmul__(self, A):
if isinstance(A, matrix):
return matrix(self.value @ A.value)
else:
return matrix(self.value @ A)
def __repr__(self):
return str(self.value)
def __getitem__(self, item):
return self.value[item]
def __setitem__(self, i, v):
self.value[i] = v
A = matrix([ [ 5, 6, 7, 5, -1],
[ 8, -4, -1, 0, -3],
[ 2, 1, -1, 3, 6],
[-9, 10, 1, -4, 6],
[ 9, 5, -5, -8, 4] ])
print("Original A:")
print(A)
print("")
A.reduce(inplace=True, debug=True)
print("A after inplace reduce function:")
print(A)
print("")
编辑
这是我试图以简单的方式重新创建的内容:
class obj:
def __init__(self, value):
self.value = value
def copy(self):
return obj(self.value)
def op(self, y, inplace=False):
if inplace:
x = self
else:
x = self.copy()
x.value += y
x.value /= y
if not inplace:
return x
def __repr__(self):
return str(self.value)
x = obj(5)
x.op(3)
print("Copy:", x)
x.op(3, inplace=True)
print("Inplace:", x)
你说像 +=
这样的运算符会就地修改对象,但这并不总是正确的。仅当运算符左侧的对象类型具有 __iadd__
方法时才会发生。如果它只有一个 __add__
方法,那么 Python 解释器将 X += Y
翻译成 X = X + Y
这通常不是就地操作。
所以你的代码没有按照你的预期执行的原因是因为你没有 __itruediv__
运算符,当你调用 A /= A_max
时(如果 normalize
是 True
),你复制了一份,尽管你打算在原地操作。
我正在为我的分配创建矩阵 class,通常如果我将变量分配为 x = self
,x 是对 self
的引用,因此所有操作到位。我有一个减少矩阵的函数,作为可选参数,我添加了 inplace=False
这样:
if inplace:
self = A
else:
A = self.copy()
现在通常我这样做的时候,如果我做A += B
这样的操作,self
就会被修改。但是我在运行A.reduce(inplace=True)
的时候,A
是没有修改的。我在下面包含了完整的 class,希望有人能告诉我为什么操作没有到位。提前致谢。
import numpy as np
class matrix:
def __init__(self, A):
self.value = np.array(A, dtype=np.float)
self.indices = np.arange(self.value.shape[0])
self.shape = self.value.shape
def swap_rows(self, r1, r2):
ind = np.arange(self.value.shape[0])
swap = (r1, r2)
ind[swap[0]] = swap[1]
ind[swap[1]] = swap[0]
temp_ind = self.indices[swap[0]]
self.indices[swap[0]] = self.indices[swap[1]]
self.indices[swap[1]] = temp_ind
self.value = self.value[ind]
def add_rows(self, operations):
# operations = [(c, row1, row2)]
# where operation will be:
# c * row1 + row2 -> row2
for c, row1, row2 in operations:
self.value[row2] += c * self.value[row1]
# ... #
def reduce(self, b_ = None, swap=True, normalize=True, return_steps=False, inplace=False, debug=False):
if inplace:
A = self
else:
A = self.copy()
if b_:
b = b_.copy()
if len(b.shape) == 1:
b.reshape((-1, 1), inplace=True)
if return_steps:
steps = []
# Normalize
if normalize:
A_max = A.row_max()
A /= A_max
if debug:
print("A after normalization:")
print(A)
print("")
if return_steps:
steps.append([('normalize', A_max)])
if b_:
b /= A_max
m, n = A.shape
for col in range(n-1):
# Swap
if swap:
# Check for max value
max_ind = np.argmax(np.abs(A[:, col]))
# Check if max is zero
if np.abs(A[max_ind, col]) < 1e-30:
print('Matrix is singular')
if b_:
return A, b
else:
return A
# Swap if necessary
if max_ind > col:
A.swap_rows(col, max_ind)
if return_steps:
steps.append([('swap', col, max_ind)])
if b_:
b.swap_rows(col, max_ind)
# Get constants
cs = -A[col+1:, col] / A[col, col]
operations = [(c, col, i+col+1) for i, c in enumerate(cs)]
if return_steps:
steps.append(operations)
A.add_rows(operations)
if b_:
b.add_rows(operations)
if debug:
print("A after row operations:")
print(A)
print("")
return_vals = np.array([A, None, None])
if b_:
return_vals[1] = b
if return_steps:
return_vals[2] = steps
if inplace:
return_vals = return_vals[1:]
if return_vals.any():
return tuple(return_vals[return_vals != None])
# ... #
def row_max(self):
return np.array([self[row, i] for row, i in enumerate(np.argmax(np.abs(self.value), axis=1))]).reshape(-1, 1)
# ... #
def copy(self):
return matrix(np.copy(self.value))
def T(self):
return matrix(self.value.T)
def inverse(self):
return matrix(np.linalg.inv(self.value))
def flip(self, axis=None, inplace=False):
if inplace:
self.value = np.flip(self.value, axis=axis)
else:
return matrix(np.flip(self.value, axis=axis))
def reshape(self, shape, inplace=False):
if inplace:
self.value = self.value.reshape(*shape)
else:
return matrix(self.value.reshape(*shape))
def __add__(self, x):
if isinstance(x, matrix):
return matrix(self.value + x.value)
else:
return matrix(self.value + x)
def __sub__(self, x):
if isinstance(x, matrix):
return matrix(self.value - x.value)
else:
return matrix(self.value - x)
def __mul__(self, x):
if isinstance(x, matrix):
return matrix(self.value * x.value)
else:
return matrix(self.value * x)
def __truediv__(self, x):
if isinstance(x, matrix):
return matrix(self.value / x.value)
else:
return matrix(self.value / x)
# ... #
def __matmul__(self, A):
if isinstance(A, matrix):
return matrix(self.value @ A.value)
else:
return matrix(self.value @ A)
def __repr__(self):
return str(self.value)
def __getitem__(self, item):
return self.value[item]
def __setitem__(self, i, v):
self.value[i] = v
A = matrix([ [ 5, 6, 7, 5, -1],
[ 8, -4, -1, 0, -3],
[ 2, 1, -1, 3, 6],
[-9, 10, 1, -4, 6],
[ 9, 5, -5, -8, 4] ])
print("Original A:")
print(A)
print("")
A.reduce(inplace=True, debug=True)
print("A after inplace reduce function:")
print(A)
print("")
编辑
这是我试图以简单的方式重新创建的内容:
class obj:
def __init__(self, value):
self.value = value
def copy(self):
return obj(self.value)
def op(self, y, inplace=False):
if inplace:
x = self
else:
x = self.copy()
x.value += y
x.value /= y
if not inplace:
return x
def __repr__(self):
return str(self.value)
x = obj(5)
x.op(3)
print("Copy:", x)
x.op(3, inplace=True)
print("Inplace:", x)
你说像 +=
这样的运算符会就地修改对象,但这并不总是正确的。仅当运算符左侧的对象类型具有 __iadd__
方法时才会发生。如果它只有一个 __add__
方法,那么 Python 解释器将 X += Y
翻译成 X = X + Y
这通常不是就地操作。
所以你的代码没有按照你的预期执行的原因是因为你没有 __itruediv__
运算符,当你调用 A /= A_max
时(如果 normalize
是 True
),你复制了一份,尽管你打算在原地操作。