Search code examples
pythonarrayslist-comprehension

Generate all combinations that sum to 1 of array of length 7


I need to find the best way to generate an array that contains all possible combinations of the values 0 to 1.0 with a 0.1 increment, where the sum of each combination is exactly equal to 1.

I have done this for array of length 3 with this code:

portfolios = []
for i in np.arange(0,1.1,0.1):
    for j in np.arange(0,1-i,0.1):
        k = 1 - i - j
        x = [i,j,k]
        portfolios.append(x)
portfolios = np.array(portfolios)

Which gives me the following

print(portfolios)
#Output:
array([[0. , 0. , 1. ],
       [0. , 0.1, 0.9],
       [0. , 0.2, 0.8],
       [0. , 0.3, 0.7],
       [0. , 0.4, 0.6],
       [0. , 0.5, 0.5],
       [0. , 0.6, 0.4],
       [0. , 0.7, 0.3],
       [0. , 0.8, 0.2],
       [0. , 0.9, 0.1],
       [0.1, 0. , 0.9],
       [0.1, 0.1, 0.8],
       [0.1, 0.2, 0.7],
       [0.1, 0.3, 0.6],
       [0.1, 0.4, 0.5],
       [0.1, 0.5, 0.4],
       [0.1, 0.6, 0.3],
       [0.1, 0.7, 0.2],
       [0.1, 0.8, 0.1],
       [0.2, 0. , 0.8],
       [0.2, 0.1, 0.7],
       [0.2, 0.2, 0.6],
       [0.2, 0.3, 0.5],
       [0.2, 0.4, 0.4],
       [0.2, 0.5, 0.3],
       ...
       [0.7, 0. , 0.3],
       [0.7, 0.1, 0.2],
       [0.7, 0.2, 0.1],
       [0.8, 0. , 0.2],
       [0.8, 0.1, 0.1],
       [0.9, 0. , 0.1]])

However, I want to do this for an array of length 7. That is, my desired output should look something like this:

#Desired output
array([[0. , 0., 0., 0., 0., 0., 1.],
       [0. , 0., 0., 0., 0., 0.1, 0.9],
       [0. , 0., 0., 0., 0., 0.2, 0.8],
       ... 
       [0.2, 0.8, 0., 0., 0., 0., 0.],
       [0.1, 0.9, 0., 0., 0., 0., 0.],
       [.1, 0., 0., 0., 0., 0., 0.]])
       

Is there a smart way to extend my previous code? Open to all suggestions and alternative approaches.


Solution

  • Here is my attempt.

    I have added comments throughout the code to help explain sections.

    Further, a text file is output at the end for your inspection of the results.

    from collections import deque
    import numpy as np
    import itertools, sys
    
    
    #We use a recursive approach to get all unique sums to 1.0
    def combinations_of_sum(n):
        result = []
        build_combinations(n, deque(), result)
    
        return result
    
    def build_combinations(sum, combinations, result):
        for i in range(sum, 0, -1):
            combinations.append(i)
            if i == sum:
                #print(list(combinations))
                adjusted_arr = [n/10 for n in list(combinations)]
                result.append(adjusted_arr)
                #print(result)
            else:
                build_combinations(sum-i, combinations, result)
            combinations.pop()
    
    
    
    
    #First, we get all the unique lists of sums,
    # ...with possibility of repeating numberes
    
    uniques = combinations_of_sum(10)
    
    #Then we filter out based on the array length you want.
    #We specify 7 here:
    array_length_limit = 7
    filtered = []
    
    for unique in uniques:
        if len(unique)<=array_length_limit:
            filtered.append(unique)
    
    #Now, we fill the filtered arrays with 0s and calculate all
    #... permutations, like  [0.7,0.3,0.0],[0.7,0.0,0.3], etc.
    
    final = []
    for arr in filtered:
        padding_length = array_length_limit - len(arr)
        arr = arr + [0]*padding_length
        
        permutations = list(set(itertools.permutations(arr,array_length_limit)))
        
        #This is just to show you what's going on
        #...You can see the permutations added to the final array.
        #print(permutations)
    
        for permutation in permutations:
            if list(permutation) not in final:
                final.append(list(permutation))
    
    
    
    #finally, convert it into a numpy array.
    final = np.array(final)
    
    print(final)
    
    np.savetxt('test.out', final, delimiter=',', fmt='%g')
    
    

    I changed the output method because there are a lot of items, so it is not convenient to view directly. Output in text file looks like:

    enter image description here

    And it goes on for a long time because of all the different permutations you wanted.

    Let me know if there are any issues and if this is what you wanted.