0

I am trying to do a simple hill climb using a knapsack problem.

I have a tweak function that's meant to return a slightly modified value of the list of binary values fed into it. I then compare this new value with the existing one to see what's better.

However, I have come across this odd issue where both current solution and new solution is being replaced with the tweaked values immediately when I try to assign the new solution as a tweaked copy of the current solution. Every list in the loop is being replaced with the same values, and I have no idea why. I have tried the same thing with other lists with the same effect. Why is this happening?

Edit: Changed from array to list

from random import randrange
import numpy as np

val = [8, 7, 6, 3, 3]
iteration = 0


def generateInitialState():
    array = []
    k=0
    while k != len(val):
        array.append(randrange(0,2))
        k+=1
    return array

CurrentSolution = generateInitialState()


def Quality(Solution):
    sum_items = 0
    newValue = np.multiply(val,Solution)
    for item in newValue:
        sum_items += item
    return sum_items

def Tweak(Solution):
    print(str(Solution) + ' : ' + str(Quality(Solution)))
    TempSolution = Solution
    if Solution[iteration] is 0:
        TempSolution[iteration] = 1
    else:
        TempSolution[iteration] = 0   
    print(str(TempSolution) + ' : ' + str(Quality(TempSolution)))
    return TempSolution 


while iteration < 5:
    iteration+=1
    NewSolution = Tweak(CurrentSolution)

    if Quality(NewSolution) > Quality(CurrentSolution):
        print('New good value detected'+ str(Quality(NewSolution)))
        CurrentSolution = NewSolution
    else:
        print('Best solution found')
        break
  • 1
    what do you think this does: `TempSolution = Solution`? – njzk2 Oct 01 '19 at 01:09
  • 2
    `TempSolution = Solution` will only assign a new name to the `Solution` array, not create a copy. See https://stackoverflow.com/questions/19676538/numpy-array-assignment-with-copy – Selcuk Oct 01 '19 at 01:09
  • Use `TempSolution = Solution[:]` to make a shallow copy of the list. BTW, none of these things are arrays, they're lists. – Barmar Oct 01 '19 at 01:11
  • BTW, Python has a built-in `sum()` function, you don't need a loop. `sum_items = sum(newValue)` – Barmar Oct 01 '19 at 01:12
  • 1
    These are not arrays, they are lists. – juanpa.arrivillaga Oct 01 '19 at 01:12
  • 1
    Also, `if Solution[iteration] is 0` is wrong. You want `if Solution[iteration] == 0` – juanpa.arrivillaga Oct 01 '19 at 01:13
  • thanks for the help guys, and Ive changed to lists instead. I was under the impression that ```TempSolution = Solution``` will just create a temp variable thats used for that specific function only. Cheers! – Sumith Inchiparambil Oct 01 '19 at 01:17
  • @Selcuk that's one of the most confusing things about Python - `=` **never** makes a copy of anything, unlike so many other languages. – Mark Ransom Oct 01 '19 at 01:18
  • That, and they insist on calling an array a list. – Mark Ransom Oct 01 '19 at 01:19
  • @SumithInchiparambil: It creates a temporary variable, but it does not create a new list object. It's important to understand that objects and variables are separate in Python, and multiple variables may refer to the same object at any time. – user2357112 Oct 01 '19 at 01:19
  • FWIW, python naming conventions are `temp_solution`, not `TempSolution`. – Mateen Ulhaq Oct 01 '19 at 01:20
  • @MarkRansom Such as which many other languages? Also it is called a list because it is a list, not an array. – Selcuk Oct 01 '19 at 01:38
  • @Selcuk C, C++, Basic, to name the first ones that come to mind. Probably any language invented before 1990. The term "list" has had a definition in computer science since nearly the beginning that is at odds with Python's definition, and "array" is the closest classic equivalent. – Mark Ransom Oct 01 '19 at 01:43
  • @MarkRansom So if we leave C out (as it can't have mutable objects, because it doesn't have objects) are we mainly talking about C++ only? Yes, it has different (less surprising but also less efficient) semantics when it comes to the assignment operator while _many other mainstream languages_ such as Python, Java, JavaScript, (possibly Rust, not sure) etc share the same assign-by-reference logic. I could agree with your second point to a certain degree. It is not an array either but maybe they could've called it a vector. – Selcuk Oct 01 '19 at 02:00

2 Answers2

0

TempSolution = Solution[:] This fixed the problem! More details in the comments

0

In Python variables are always references to objects, not the objects themselves. An object is a piece of data residing in memory or which could at least be imagined as such. In Python terms it is said "the variable is bound to the object".

If you assign one variable to another like TempSolution = Solution you copy the reference to the very same (list) object. In other words, both variables are now bound to the same list in memory and it doesn't matter if you alter the list through one variable or the other.

To copy the object itself, take a look at the copy standard library of Python (https://docs.python.org/3/library/copy.html). It provides the functions copy and deepcopy. The first copies an object but not the references inside, while the latter copies recursively all references.

So, I would suggest:

import copy

# ...

def Tweak(Solution):
    # ...
    TempSolution = copy.copy(Solution)

IMHO, opposed to TempSolution = Solution[:] this expresses more clearly that you intend to copy the list.

bjhend
  • 1,538
  • 11
  • 25