Чудеса при передаче списка в функцию в Python

5065584

Есть код на Python, который считает собственные значения квадратной матрицы matr1, используя QR-разложение:

dim=len(matr1)
oldl=[1.0 for i in range(dim)]
diff=oldl[:]
flag=1
opmatrix=[[matr1[i][j] for j in range(dim)] for i in range(dim)]
print matrixtostring(opmatrix,field=6)
count=0
while (flag != 0):
qr=qrdecomp(matr1)
matr1=multiplymatrix(qr[1],qr[0])
diff=[matr1[i][i]-oldl[i] for i in range(dim)]
oldl=[matr1[i][i] for i in range(dim)]
flag=0
for i in range(dim):
if (abs(diff[i]) > prec):
flag+=1
count+=1
print count
print diff
print matr1

Здесь matr1 - список из dim списков, каждый длиной dim. qrdecomp - функция, вычисляющая QR-разложение, она работает правильно. Если этот код сидит в теле программы, он работает верно, относительно быстро сходясь к верхнетреугольной матрице, у которой по диагонали собственные значения (как оно и должно быть) Если его внести в функцию:

def eigenvalue(matrix,prec=5): #Поиск собственных значений методом QR-разложения
dim=len(matrix)
e=0.5*(0.1**prec)
oldl=[1.0 for i in range(dim)]
diff=oldl[:]
flag=1
count=0
while (flag != 0):
qr=qrdecomp(matrix)
matrix=multiplymatrix(qr[1],qr[0])
diff=[matrix[i][i]-oldl[i] for i in range(dim)]
oldl=[matrix[i][i] for i in range(dim)]
flag=0
for i in range(dim):
if (abs(diff[i]) > e):
flag+=1
count+=1
print countтра
print diff
print matrixtostring(matrix,field=6)
return [matrix[i][i] for i in range(dim)]

то перестает работать, то есть схождения нет, зато есть нарастание элементов матрицы. Дело именно в передаче матрицы как параметра. Объясните, есть ли какие-нибудь чудеса в Python при передаче списков чисел с плавающей точкой?

kedr1983

print countтра
Это что за строчка внутри второго примера?
Еще бы знать, откуда фунции (qrdecomp, multiplymatrix). Импортируются или самописные?
Если в твоем примере matrix — список списков, то он передается в качестве ссылки.
Как будет работать следующий код?

from copy import deepcopy
def eigenvalue(matrix,prec=5):
matr1 = deepcopy(matrix)
dim=len(matr1)
e=0.5*(0.1**prec)
oldl=[1.0 for i in range(dim)]
diff=oldl[:]
flag=1
count=0
while (flag != 0):
qr=qrdecomp(matr1)
matr1=multiplymatrix(qr[1],qr[0])
diff=[matr1[i][i]-oldl[i] for i in range(dim)]
oldl=[matr1[i][i] for i in range(dim)]
flag=0
for i in range(dim):
if (abs(diff[i]) > e):
flag+=1
count+=1
print count
print diff
print matrixtostring(matr1,field=6)
return [matr1[i][i] for i in range(dim)]

5065584

print countтра
это опечатка, естественно,
 print count 

Функции qrdecomp, multiplymatrix самописные и находятся в том же файле, что и обсуждаемый кусок кода.
Приведенный вами код был опробован, не работает. Что-то происходит именно при передаче списка в функцию. Если пользоваться передаваемым списком как глобальной переменной
 global matrix 

то все работает верно

s507040

выглядит так, будто matrix меняется где-то кроме того куска, который переносится в функцию и перестает работать.
нет ли в модуле какого-нибудь забытого кода вне функций?

5065584

будто matrix меняется где-то кроме того куска, который переносится в функцию и перестает работать.
нет ли в модуле какого-нибудь забытого кода вне функций?
А ведь вы правы, милостивый государь! Действительно, в функции qrdecomp было место, где обрабатывался не параметр, а глобальная переменная matr1. Причем matr1 не объявлялась как глобальная, а функция типа работала. Было так:
def qrdecomp(matrix):
dim=len(matrix)
R=[[0.0 for i in range(dim)] for j in range(dim)]
Q=[[0.0 for i in range(dim)] for j in range(dim)]

for i in range(dim):
R[i][i]=euclidnorm([matrix[k][i] for k in range(dim)])
for k in range(dim):
Q[k][i]=matrix[k][i]/R[i][i]
for j in range(i+1,dim):
R[i][j]=0.0
for k in range(dim):
R[i][j]=R[i][j]+Q[k][i]*matrix[k][j]
for k in range(dim):
matr1[k][j]=matrix[k][j]-Q[k][i]*R[i][j]
return [Q,R]

А вместо
matr1[k][j]=matrix[k][j]-Q[k][i]*R[i][j]  

должно быть
matrix[k][j]=matrix[k][j]-Q[k][i]*R[i][j]  

Большое спасибо

beluchy

ты это в качестве упражнения реализуешь или в работе использовать собираешься?

bleyman

Заведи за правило

...

def main:
    variable = stuff
    ...
    do_stuff
    ...

if __name__ == '__main__':
    main

Тогда все переменные которые ты используешь оказываются локальными переменными функции main и никакой левой херни не происходит. Определение левой херни: переменная используется без каких-либо явных проблем (вроде эксепшена что нет такой) если она определена ниже по коду чем используется. В модуле такое допустимо для функций (которые тоже на самом деле переменные, точнее, имена) всё остальное — левая херня. Объявление всех переменных которые не функции в начале модуля и скрывание всех остальных в локальных переменных функции main помогает не писать неведомой сексуальной херни.
Оставить комментарий
Имя или ник:
Комментарий: