views:

1675

answers:

7

Here is my sample code. It is meant to be an iterative procedure for gauss seidel (matrix solver). Essentially when the error is small enough it breaks out of the while loop.

i=1
while (i>0):
    x_past = x_present

    j=0
    while(j<3):
        value=0
        k=0
        while(k<3):
            if(k!=j):
                if(i==1):
                    if(k>j):
                        value=value+0
                    else:
                        value=value+x_present[k]*eqn[j][k]    
                else:
                    value=value+x_present[k]*eqn[j][k]
            else:
                value=value+eqn[j][k]
            k=k+1
        x_present[j:j+1]=[value]
        j=j+1
    print "X_PAST"
    print x_past
    print "X_PRESENT"
    print x_present    
    if(error(x_past, x_present)<10**-2):
        break;
    i=i+1

I've reduced the code so its more manageable. if you don't understand what its doing its not really that important to solving this problem.

Here is the issue. Everytime

x_present[j:j+1]=[value]

is run, x_past is made equal to x_present. I don't know why this is the case as the only place i have set x_past equal to x_present is at the top of the loop. If I take away the

x_past=x_present

sentence, x_past is never made equal to x_present. This leads me to think it is some combination of the two statements that is causing the issue.

This is a big problem cause if x_past = x_present the error = 0 every time and the loop breaks after the first iteration. The code does work, for example if I tell the code to run for 8 iterations and the break it gives me the answer its supposed to.

I've been trying to figure this out for the last 4 hours and am completely stumped. I haven't been working with python long, so my trouble shooting skills syntax wise aren't that great. Any help would be appreciated!!

+3  A: 

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...

Jon Skeet
I'm thinking your right on this one.
Unkwntech
Yes, but still: giving an answer and then admitting it could be "totally wrong" doesn't add any useful information to the discussion.
hop
@hop: Yes it does - it gives a suggestion for the OP to try. Three options here: 1) Don't say anything - that's no help at all. 2) Say something, without explaining the uncertainty. False confidence isn't a good thing. 3) Explain the uncertainty (as I did) - it's honest, and doesn't give false hope.
Jon Skeet
A: 

It looks as if x_present is a list. I suspect that this means that the assignment x_last = x_present makes x_last into an alias, i.e. they reference the same variable. Might this be the case?

unwind
there are no variables in python, only names. and definitely no aliases.
hop
@hop: If you introduce several name bindings to a single object it could be considered as an aliasing. And at least the term "free variable" is present in Python.
J.F. Sebastian
+23  A: 

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[:].

>>> x_past = x_present[:]
>>> x_past
[4, 5, 6, 7]
>>>
>>> x_present.append(8)
>>>
>>> x_past
[4, 5, 6, 7]
monkut
A: 

try changing the x_past = x_present line to x_past = [x for x in x_present] and see if it helps.

the list copy shorthand is my favorite python feature since i can do one-liners that are not possible in other languages:

greaterthan100 = [x for x in number if x > 100]

notinblacklist = [x for x in mylist if x not in blacklist]

firstchildofbigfamily = [x.child[0] for x in familylist if len(x.child) > 10]

Lukman
A: 

I would go with monkut and Jon Skeet answer.

And I have a question and advice :)

  1. How you managed to get out from while loop if you increment variable i every time?

  2. Use debugger :)

I tried pydev for Eclipse and it's doing a nice job.

hf

Chobicus
A: 

In Python, everything is an object. So the statement x_past = x_present point to the same reference.

Dr. Hfuhruhurr
Not true at all.>> x = 5>> y = x>> x = 8>> print x,y8 5
kigurai
And of course the comment system screwed up my newlines...
kigurai
@kigural: You are confused. Reassigning x does of course not affect y. eddy's point is that if you change the *object* that x points to, the apparent value of y will change too, which is correct.
Deestan
Yes, that is right. My bad.
kigurai
+3  A: 

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)))
J.F. Sebastian
thanks for the earlier soln for copying the lists.However the code you gave me to replace the code I have up there does not work. The issue seems to be in the x_present[j]= sum(x_present[k] ...
darudude
@darudude: The code `sum(..` requires Python version >= 2.5 What version do you use?
J.F. Sebastian
I have python 2.5.2
darudude
@darudude: I've checked there is no syntax errors on Python 2.5.2 in the above code. I don't know whether the semantics is correct. The above code is a mere illustration how a Python code differs from a C, Fortran -style code.
J.F. Sebastian