Kdog
Kdog

Reputation: 513

Generate Numpy array of even integers that sum to a value

Is there a numpy solution that would allow you to initialize an array based on the following conditions?

  1. Number of elements in axis 1. (In the example below you have 4 places in each element of the array)
  2. Sum of values. (All elements sum to 8)
  3. Step size. (Using increments of 2)

Essentially this shows all the combinations of 4 values you can add to achieve the wanted sum (8) at a step size of 2.

My experiments fail when I set the axis 1 dimension to over 6 and the sum to over 100. There has to be a better way to do this than what I've been trying.

array([[0, 0, 0, 8],
       [0, 0, 2, 6],
       [0, 0, 4, 4],
       [0, 0, 6, 2],
       [0, 0, 8, 0],
       [0, 2, 0, 6],
       [0, 2, 2, 4],
       [0, 2, 4, 2],
       [0, 2, 6, 0],
       [0, 4, 0, 4],
       [0, 4, 2, 2],
       [0, 4, 4, 0],
       [0, 6, 0, 2],
       [0, 6, 2, 0],
       [0, 8, 0, 0],
       [2, 0, 0, 6],
       [2, 0, 2, 4],
       [2, 0, 4, 2],
       [2, 0, 6, 0],
       [2, 2, 0, 4],
       [2, 2, 2, 2],
       [2, 2, 4, 0],
       [2, 4, 0, 2],
       [2, 4, 2, 0],
       [2, 6, 0, 0],
       [4, 0, 0, 4],
       [4, 0, 2, 2],
       [4, 0, 4, 0],
       [4, 2, 0, 2],
       [4, 2, 2, 0],
       [4, 4, 0, 0],
       [6, 0, 0, 2],
       [6, 0, 2, 0],
       [6, 2, 0, 0],
       [8, 0, 0, 0]], dtype=int64)

Upvotes: 1

Views: 269

Answers (2)

bousof
bousof

Reputation: 1251

Here is a small code that will enable you to loop over the desired combinations. It takes 3 parameter:

  • itsize: Number of elements.
  • itsum: Sum of values.
  • itstep: Step size.

It may be necessary to optimize it if the computations you do in the FOR loop are light. I loop over more combinations than necessary (all the i,j,k,l that take values in 0,itstep,2*itstep,...,itsum) and keep only those verifying the condition that all sum up to itsum. The big size array is not computed and the rows are computed on-the-fly when iterating so you will not have the memory troubles:

class Combinations:
  def __init__(self, itsize, itsum, itstep):
    assert(itsum % itstep==0) # Sum is a multiple of step
    assert(itsum >= itstep) # Sum bigger or equal than step
    assert(itsize > 0) # Number of elements >0
    self.itsize = itsize # Number of elements
    self.itsum = itsum # Sum parameter
    self.itstep = itstep # Step parameter
    self.cvalue = None # Value of the iterator
  def __iter__(self):
    self.itvalue = None
    return self
  def __next__(self):
    if self.itvalue is None: # Initialization of the iterator
      self.itvalue = [0]*(self.itsize)
    elif self.itvalue[0] == self.itsum: # We reached all combinations the iterator is restarted
      self.itvalue = None
      return None
    while True: # Find the next iterator value
      for i in range(self.itsize-1,-1,-1):
        if self.itvalue[i]<self.itsum:
          self.itvalue[i] += self.itstep
          break
        else:
          self.itvalue[i] = 0
      if sum(self.itvalue) == self.itsum:
        break
    return self.itvalue # Return iterator value

myiter = iter(Combinations(4,8,2))

for val in myiter:
  if val is None:
    break
  print(val)

Output:

% python3 script.py
[0, 0, 0, 8]
[0, 0, 2, 6]
[0, 0, 4, 4]
[0, 0, 6, 2]
[0, 0, 8, 0]
[0, 2, 0, 6]
[0, 2, 2, 4]
[0, 2, 4, 2]
[0, 2, 6, 0]
[0, 4, 0, 4]
[0, 4, 2, 2]
[0, 4, 4, 0]
[0, 6, 0, 2]
[0, 6, 2, 0]
[0, 8, 0, 0]
[2, 0, 0, 6]
[2, 0, 2, 4]
[2, 0, 4, 2]
[2, 0, 6, 0]
[2, 2, 0, 4]
[2, 2, 2, 2]
[2, 2, 4, 0]
[2, 4, 0, 2]
[2, 4, 2, 0]
[2, 6, 0, 0]
[4, 0, 0, 4]
[4, 0, 2, 2]
[4, 0, 4, 0]
[4, 2, 0, 2]
[4, 2, 2, 0]
[4, 4, 0, 0]
[6, 0, 0, 2]
[6, 0, 2, 0]
[6, 2, 0, 0]
[8, 0, 0, 0]

Upvotes: 1

Gregory Starr
Gregory Starr

Reputation: 1

I tried this out and also found that it slowed down significantly at that size. I think part of the problem is that the output array gets pretty large at that point. I'm not 100% sure my code is right, but the plot shows how the array size grows with condition 2 (sum of values in each row). I didn't do 100, but it looks like it would be about 4,000,000 rows

plot

Upvotes: 0

Related Questions