0

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.

Aleks
  • 378
  • 1
  • 3
  • 10
  • Does order matter? i.e. as long as you have all unique combinations it is fine? Also, after an array of a certain length, aren't you only adding on more zeroes? For instance, after array of length 5 (.1+.2+.3+.4+.5>1, the 5 minimum positive increments), no sum of .1 increments is less than 1 so there are no new combinations? – Richard K Yu Jan 04 '22 at 14:00
  • 1
    @RichardKYu Order matters. Ex: In the length 3 case with the numbers say 0.7, 0.3 and 0.0, I want to genereate all combinations: [0.7,0.3,0.0],[0.7,0.0,0.3],[0.3,0.7,0.0][0.3,0.0,0.7],[0.0,0.3,0.7],[0.0,0.7,0.3]. However, the order of these combinations does not matter. Further, array of length 7 may look like: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.4], meaning that numbers can be repeated. – Aleks Jan 04 '22 at 14:23

1 Answers1

1

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.

Richard K Yu
  • 2,152
  • 3
  • 8
  • 21