Generate sets of numbers with a predefined sum

Asher Bay's icon

For a rhythmic sequence generator, I want to generate sets of (semi)random integers which each have the same predefined sum. For example, if 10 is my target sum, the generator might output "2 5 2 1" or "1 1 4 1 3."
How could I achieve this? I could loop the generator and reject number sets that don't add up to the target sum until one does, but that seems inefficient.

Chris Rolfe's icon

In a step sequencer, you're just counting the delay times between beats:

1 2 3 4 5 6 7 8 9 10
- x - - - - x - x - x
- 2- - - - 5 - 2 - 1

Here's one way to implement it (a bitmap would also work):

1. Generate N-1 sorted, unique random numbers (urn) from 1 to 9. E.g., 1 4 7
2. Pad w/ 0 and 10; 1 4 7 -> 0 1 4 7 10.
3. Take the deltas: 0 1 4 7 10 -> 1 3 3 3

and a quick-and-dirty patcher.

Max Patch
Copy patch and select New From Clipboard in Max.


Of course, any set thus generated can be shuffled, reversed, etc. w/ zl list ops to make variations.

Asher Bay's icon

Thank you for the reply! In the patcher you posted though, the resulting sets of numbers often have different sums. My goal is to have each generated set have a uniform, user-definable sum. Does that make sense?

Asher Bay's icon

I also want the quantity of numbers in each set be (semi)randomly determined

Chris Rolfe's icon

These add up to 10 (check you have the patcher I just uploaded, not the first one):

print: 7 1 1 1
print: 1 5 1 3
print: 4 2 3 1
print: 1 1 1 7
print: 1 4 2 3
print: 1 2 1 6
print: 4 4 1 1
print: 5 1 1 3
print: 2 1 2 5
print: 1 1 2 6
print: 1 2 3 4

or, with groups of 7:

print: 2 1 1 1 1 3 1
etc.

Or change two numbers and make 'em add up to 5:

print: 2 2 1
print: 2 1 2
print: 1 3 1

Chris Rolfe's icon

Randomized group sizes:

Max Patch
Copy patch and select New From Clipboard in Max.

outputs

print: 5 3 2
print: 3 3 2 2
print: 2 3 1 2 2
print: 1 4 2 1 2
print: 7 2 1
print: 1 5 1 3
etc.

Valery_Kondakoff's icon

Here is another approach (javascript function to be used in js object):

// num - given number
// step - incremental step
// cnt - counter (next location in array)
// arr - array to store the combination
function getNumbers(num, step, cnt, arr) {
    if (cnt > num || step > num) {
        return;
    } else if (cnt == num) {
        // if counter cnt reached num print the list
        console.log(arr);
        return;
    } else {
        // else append the step size to list
        arr.push(step);
        // increment the cnt by step and recurse
        getNumbers(num, step, cnt + step, arr);
        // remove the last step item from list
        arr.pop();
        // increment the step size and recurse
        getNumbers(num, step + 1, cnt, arr);
    }
}

Here is the output of getNumbers(10, 1, 0, []) (to be shuffled, reversed, etc. with zl list ops to make variations):

[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
[ 1, 1, 1, 1, 1, 1, 1, 1, 2 ]
[ 1, 1, 1, 1, 1, 1, 1, 3 ]
[ 1, 1, 1, 1, 1, 1, 2, 2 ]
[ 1, 1, 1, 1, 1, 1, 4 ]
[ 1, 1, 1, 1, 1, 2, 3 ]
[ 1, 1, 1, 1, 1, 5 ]
[ 1, 1, 1, 1, 2, 2, 2 ]
[ 1, 1, 1, 1, 2, 4 ]
[ 1, 1, 1, 1, 3, 3 ]
[ 1, 1, 1, 1, 6 ]
[ 1, 1, 1, 2, 2, 3 ]
[ 1, 1, 1, 2, 5 ]
[ 1, 1, 1, 3, 4 ]
[ 1, 1, 1, 7 ]
[ 1, 1, 2, 2, 2, 2 ]
[ 1, 1, 2, 2, 4 ]
[ 1, 1, 2, 3, 3 ]
[ 1, 1, 2, 6 ]
[ 1, 1, 3, 5 ]
[ 1, 1, 4, 4 ]
[ 1, 1, 8 ]
[ 1, 2, 2, 2, 3 ]
[ 1, 2, 2, 5 ]
[ 1, 2, 3, 4 ]
[ 1, 2, 7 ]
[ 1, 3, 3, 3 ]
[ 1, 3, 6 ]
[ 1, 4, 5 ]
[ 1, 9 ]
[ 2, 2, 2, 2, 2 ]
[ 2, 2, 2, 4 ]
[ 2, 2, 3, 3 ]
[ 2, 2, 6 ]
[ 2, 3, 5 ]
[ 2, 4, 4 ]
[ 2, 8 ]
[ 3, 3, 4 ]
[ 3, 7 ]
[ 4, 6 ]
[ 5, 5 ]
[ 10 ]