Назначение переменной = самостоятельное создание копии.Нужно ли это быть ссылкой (указатель) - PullRequest
0 голосов
/ 28 февраля 2019

Я работаю над созданием класса матрицы для присваивания, которое у меня есть, и обычно, если я назначаю переменную как x = self, x является ссылкой на self, и, таким образом, все операции выполняются.У меня есть функция, которая уменьшает матрицу, и в качестве необязательного параметра я добавил inplace=False такой, что:

if inplace:
    self = A
else: 
    A = self.copy()

Теперь обычно, когда я делаю это, если бы я должен был сделать такую ​​операцию, как A += B, self будет изменено.Однако, когда я запускаю A.reduce(inplace=True), A не изменяется.Я включил полный класс ниже и надеюсь, что кто-нибудь скажет мне, почему операции не происходят на месте.Заранее спасибо.

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)

1 Ответ

0 голосов
/ 01 марта 2019

Вы говорите, что операторы типа += изменяют объекты на месте, но это не всегда так.Это происходит только в том случае, если тип объекта в левой части оператора имеет метод __iadd__.Если у него есть только метод __add__, то интерпретатор Python переводит X += Y в X = X + Y, что обычно не является операцией на месте.

Так что причина в том, что ваш код не выполняет то, что вы ожидаетепотому что у вас нет оператора __itruediv__, и когда вы звоните A /= A_max (если normalize равен True), вы делаете копию, несмотря на свое намерение работать на месте.

...