Python - one variable equals another variable when it shouldn't
Yes, I think the answers here show your problem. Just to try and clarify a little bit.
You're referencing a list, so when the list changes any reference to that list will reflect that change. To demonstrate:
>>> x_present = [4,5,6]
>>>
>>> x_past = x_present
>>>
>>> x_past
[4, 5, 6]
>>>
>>> x_present.append(7)
>>>
>>> x_past
[4, 5, 6, 7]
>>>
If you want a copy of the list you have to do do this, listcopy = mylist[:]. (or 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]
What are x_past and x_present? I don't know much Python, but from a .NET/Java perspective, if they're references to some data structure (a map or whatever) then making them references to the same object (as you do at the start) will mean that any changes made through one variable will be visible through the other. It sounds like you need to take a copy of the data structure instead of just doing a reference assignment. Does the data structure you're working with have any kind of "clone" functionality available?
As I say though, I don't know much Python so this could be totally wrong...
As others pointed out the answer is to replace: x_past = x_present
by x_past = x_present[:]
. In general you could use a copy
module to copy an object in 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]
Your code is unpythonic to say the least.
It could be replaced by something like the following code:
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
Here's a definition of allequal()
(using an absolute error. It might or might not be a good idea in your case (you could use a relative error instead)):
def allequal(x, y, tolerance):
return (len(x) == len(y) and
all(-tolerance < (xx - yy) < tolerance
for xx, yy in zip(x, y)))