1

So I'm encountering a weird problem.

def findFourPlus(itemCount, seq, goal):
    goalDifference = float("inf")
    closestPartial = []
    hello = subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial=[])
    return hello #doesn't return value from subset_sum()

def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
    s = sum(partial)

    # check if the partial sum is equals to target
    if(len(partial) == itemCount):
        if s == goal:
                print("FOUND YAA")
                return partial #right now doesn't return anything. I intend for it to break out of this function as soon as it finds one pair of solution. 


        else:
            if( abs(goal - s) < goalDifference):
                #print(abs(goal-s), goalDifference, closestPartial)
                goalDifference = abs(goal - s)
                closestPartial[:] = partial
                #print(abs(goal-s), goalDifference, closestPartial)
                return closestPartial

    for i in range(len(seq)):
        n = seq[i]
        remaining = seq[i+1:]
        print(subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n]))

In the subset_sum() function, I can print out the partial variable, and it will return to me the right value

>>> findFourPlus(3, [1,2,3,4,5,6,7,8,9,10], 20)
FOUND YAA
[1, 9, 10]
FOUND YAA
[2, 8, 10]
FOUND YAA
[3, 7, 10]
FOUND YAA
[3, 8, 9]
FOUND YAA
[4, 6, 10]
FOUND YAA
[4, 7, 9]
FOUND YAA
[5, 6, 9]
FOUND YAA
[5, 7, 8]

However, if i change the print(partial) line to return partial, it will still print out the FOUNDYAA line since it is printed, but it will not return the partial

>>> findFourPlus(3, [1,2,3,4,5,6,7,8,9,10], 20)
FOUND YAA
FOUND YAA
FOUND YAA
FOUND YAA
FOUND YAA
FOUND YAA
FOUND YAA
FOUND YAA

I wrote other functions before I wrote findFourPlus and subset_sum, and those worked fine when I attempt to return something. What am i doing wrong here?

Edit: I seem to be confusing the readers here. What I am ultimately trying to do is to store the sets of integeres (the list ) in a variable by calling the findFourPlus() function. Say I want to see if, in the list [1,2,3,4,5], would any two of them add up equal 5, I would call findFourPlus(2, [1,2,3,4,5], 5), and it would hopefully return to me [1, 4]. With that, I can store the answer [1,4] into a variable, say answer, by calling

answer = findFourPlus(2, [1,2,3,4,5], 5) // if I call answer, it'll return to me [1,4]

An example:

>>> a = findFourPlus(2, [1,2,3,4,5], 6) # prints out everything, which is good for test cases
[1, 2]
[1, 3]
[1, 4]
FOUND YAA
[1, 5]
None
[2, 3]
FOUND YAA
[2, 4]
[2, 5]
None
[3, 4]
[3, 5]
None
[4, 5]
None
None
>>> a # doesn't return anything when called
>>> 

The printing are all just to make sure my logic is correct. Sorry for the confusion, but hopefully this clarifies it!

user3277633
  • 1,891
  • 6
  • 28
  • 48
  • So I'm not entirely sure what you think your code is supposed to be doing, but its not making a whole lot of sense. even if you add the return in `subset_sum`, its not guaranteed to return. On top of that, `if(len(partial) == itemCount)` will only ever be true if you pass 0 as `itemCount`, as you are always passing an empty list for `partial`. I would recommend that you start again. – user2085282 Sep 22 '14 at 18:36
  • @user2085282 that does seem like the best course of action right now doesn't it. Are there any non-recursive approach of the subset_sum problem? – user3277633 Sep 22 '14 at 18:37
  • have you read http://en.wikipedia.org/wiki/Subset_sum_problem – user2085282 Sep 22 '14 at 18:40
  • 1
    Can you fix the indentation in subset_sum? Its hard to tell what its doing. Also, can you update the code to the failing case with the return? Its hard to figure out the problem from the working case. Doing both `print(partial)` and `return partial`, plus printing the result in findFourPlus would be helpful. – tdelaney Sep 22 '14 at 18:44
  • I've updated the code ! please let me know if you need any additional info – user3277633 Sep 22 '14 at 18:56
  • There certainly are non-recursive ways to generate subsets! I'll post some code if you want to see it. But as the Wiki article say, solving the subset sum problem efficiently in general is a hard problem. Still, a relatively simple algorithm is ok for well-behaved data sets, especially if we restrict the number of elements in the subsets, like you are doing here. – PM 2Ring Sep 23 '14 at 15:07

4 Answers4

3

When you execute a function, it doesn't automatically dump its return value into output, so in your for loop,

for i in range(len(seq)):
    n = seq[i]
    remaining = seq[i+1:]
    print(subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n]))
user2085282
  • 1,077
  • 1
  • 8
  • 16
  • thanks for the suggestions. But this only prints out every possible iteration. If i set a variable var to findFourPlus(), var still returns nothing when I call on it. What I am ultimately trying to do is to manipulate the data stored in the var variable, but this only prints out the data – user3277633 Sep 22 '14 at 18:15
  • 1
    I'm not quite sure what you are trying to ask. are you trying to keep the result of each call to `subset_sum`? What do you mean 'var returns nothing', variables don't return anything, they just hold a value. – user2085282 Sep 22 '14 at 18:18
  • I added an edit to my original question. So sorry for the confusion, but hopefully the edit will clarify it! – user3277633 Sep 22 '14 at 18:23
2

You are doing recursive calls to subset_sum, but you are not passing the returned value from the subcall to the caller.

If you add a return statement in the loop for recursive calls, you get what you are searching for, if the subcall found something.

I don't see the need for the closestPartial, because if you set it to inf, the function returns the first sequence that contains itemcount elements. I've also changed the test to <= to work with 0.

def findFourPlus(itemCount, seq, goal):
    goalDifference = float("inf")
    closestPartial = []
    hello = subset_sum(itemCount, seq, goal, 0, closestPartial, partial=[])
    return hello #doesn't return value from subset_sum()

def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):
    s = sum(partial)

    # check if the partial sum is equals to target
    if(len(partial) == itemCount):
        if s == goal:
                print("FOUND YAA")
                return partial #right now doesn't return anything. I intend for it to break out of this function as soon as it finds one pair of solution. 


        else:
            if( abs(goal - s) <= goalDifference):
                #print(abs(goal-s), goalDifference, closestPartial)
                goalDifference = abs(goal - s)
                closestPartial[:] = partial
                #print(abs(goal-s), goalDifference, closestPartial)
                return closestPartial

    for i in range(len(seq)):
        n = seq[i]
        remaining = seq[i+1:]
        t = subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])
        print t
        if t:
            return t

a = findFourPlus(2, [1,2,3,4,5], 6)
print "a=", a

Output :

None
None
None
None
None
None
None
None
None
None
None
None
None
None
FOUND YAA
[1, 5]
[1, 5]
a= [1, 5]
Mickaël Bucas
  • 683
  • 5
  • 20
  • thank you so much for fixing this problem that i've been struggling on. How would you suggest I go on implementing the a functionality that is similar to closestPartial? I am still trying to get a list of integers that, when add up, will be the closest to the sum required – user3277633 Sep 23 '14 at 19:44
1

Some execution paths of subset_sum don't have a return statement, so None will be returned (and forwarded by findFourPlus). In the interpreter, evaluating None does not print anything:

>>> def f():
...  pass
...
>>> a = f()
>>> a is None
True
>>> a
>>>

If you want to be sure to see something, try:

>>> str(a)
'None'
Gnurfos
  • 980
  • 2
  • 10
  • 29
0
def subset_sum(itemCount, seq, goal, goalDifference, closestPartial, partial):

    s = sum(partial)

    # check if the partial sum is equals to target
    if(len(partial) == itemCount):
        if s == goal:
                print("FOUND YAA")
                print(partial)
                return partial
        else:
            if( abs(goal - s) < goalDifference):
                #print(abs(goal-s), goalDifference, closestPartial)
                goalDifference = abs(goal - s)
                closestPartial[:] = partial
                #print(abs(goal-s), goalDifference, closestPartial)

for i in range(len(seq)):
    n = seq[i]
    remaining = seq[i+1:]
    result = subset_sum(itemCount, remaining, goal, goalDifference, closestPartial, partial + [n])
    if result:    ## If you just want the
        break     ## first one
else:
    print ("Nothing found")
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • thanks for the suggestion. As the answer above, this appears to be printing out the list of subset_sums available. If I store findFourPlus() into a variable and call that variable, it doens't seem to be returning anything. What I am trying to ultimately do is to manipulate the data stored in the varialbe! hope this clarifies my problem – user3277633 Sep 22 '14 at 18:18
  • It _is_ returning the result, but `findFourPlus()` doesn't have a loop. Do you mean to accumulate the results in a list? – John La Rooy Sep 22 '14 at 18:32
  • I am fine with it just returning the first one it gets when s == goal, but i've been trying to get even that functionality to work and so far i've been failing – user3277633 Sep 22 '14 at 18:33