For loop writing over part, but not all, of previous entry in array

74 views Asked by At

I'm writing a pretty simple random walk function. Whole code is below. I'm using an array to keep track of the parameter values when the current cost function is less than the previous. But for some reason, the array that's tracking the output is rewriting? previous entries. I think it has something to do with appending the parameters as "c", and so there's a memory allocation issue because "c" is appended instead of the values of c, but I don't know how to fix this, nor why it would be different with the cost function value psi, which is appending and maintaining its values as intended.

I'm trying to create something like:

input: 
for n in N: 
if cost < previous cost: keep current parameters
write current parameters & cost to tracking list

output:
n = 0, parameters = [1,2,3], cost = 4.5, track = [([1,2,3], 4.5)]
n = 1, parameters = [1.1,2.4,2.7], cost = 3.9, track = [([1,2,3], 4.5), ([1.1, 2.4, 2.7], 3.9)]
etc

instead, what I'm getting is

output:
n = 0, parameters = [1,2,3], cost = 4.5, track = [([1,2,3], 4.5)]
n = 1, parameters = [1.1,2.4,2.7], cost = 3.9, track = [([1.1,2.4,2.7], 4.5), ([1.1, 2.4, 2.7], 3.9)]

so it's replacing the parameters, but keeping the previous cost. This happens when the track function is outside of the success (lower cost) if statement, too.

help ?

#pure random walk where all c parameters are randomly updated at once; no restrictions on pos/neg of parameters
del track
del bigtrack

c = [5,5,-5]
cp = c
kB = -8

M = 10
N = 5000
bigtrack = []

psip = cost(LN, LB, dldtN, dldtB, c[2], kB, c[0], c[1]) #cost using initialized parameters

for m in range(M):

    track = []
    for n in range(N):

        for i in range(len(c)):
            rand = np.random.uniform(-1,1)
            c[i] = c[i] + rand
            #print(c[i])
        #print("parameters = ", c)

        psi = cost(LN, LB, dldtN, dldtB, c[2], kB, c[0], c[1])
        #print("new cost = ", psi)

        if psi < psip:
            cp = c
            resp = res
            psip = psi
            track.append((c, psi))
            print("tracking function: \n", track)
        else:
            c = cp #keep prior 
            res = resp
            psi = psip

        if psi <16:
            print("VICTORY")
            break


    #print(track)
    #if track != []:
    bigtrack.append((track, m))

and here's a sample output

tracking function: 
 [([4.145180382591114, 5.194803875207629, -5.77417154313107], 457.37070071446328)]
tracking function: 
 [([4.366620027701061, 5.610886161756634, -6.300451985366614], 457.37070071446328), ([4.366620027701061, 5.610886161756634, -6.300451985366614], 406.27520117896)]
tracking function: 
 [([4.294900222966394, 6.104004008230176, -6.636360393709489], 457.37070071446328), ([4.294900222966394, 6.104004008230176, -6.636360393709489], 406.27520117896), ([4.294900222966394, 6.104004008230176, -6.636360393709489], 377.1702411076343)]
1

There are 1 answers

0
niemmi On BEST ANSWER

You're inserting the same list to the results while modifying it in between insertions. Effectively you're doing following:

>>> track = []
>>> c = [1, 2, 3]
>>> track.append(c)
>>> track
[[1, 2, 3]]
>>> c[1] += 2
>>> track.append(c)
>>> track
[[1, 4, 3], [1, 4, 3]]

In order to fix the issue you could copy the list every time it's appended to the results:

track.append((c[:], psi)) # instead of track.append((c, psi))