How to split a number N into M random positive parts whose sum is exactly N in Python

1 Answer

0 votes
import random

"""
    Split a number N into M random positive parts that sum to N.
 
    Algorithm (uniform integer composition):
    ----------------------------------------
    1. We want M positive integers p1, p2, ..., pM such that:
           p1 + p2 + ... + pM = N
 
    2. Generate (M - 1) random "cut points" in the range [1, N - 1].
       Example: N = 20, M = 4 → generate 3 cuts, e.g. {3, 11, 17}
       
    3. Sort the cut points.
 
    4. The parts are the differences between consecutive cuts:
         p1 = cut[0]
         p2 = cut[1] - cut[0]
         ...
         pM = N - cut[M-2]
 
    This produces a uniformly random composition of N into M parts.
"""

"""
    Important:
    -----------
    Random cut points must be UNIQUE.
    If two cut points are equal, their difference becomes 0,
    which produces an invalid part.
"""

# Generate M random positive parts summing to N
def split_into_random_parts(N, M):
    if M <= 0 or N < M:
        raise ValueError("Invalid N or M: require N >= M >= 1")

    cuts = []
    used = set()   # ensures uniqueness

    # Generate UNIQUE cut points
    while len(cuts) < M - 1:
        c = random.randint(1, N - 1)
        if c not in used:
            used.add(c)
            cuts.append(c)

    # Sort the cut points
    cuts.sort()

    # Build the parts
    parts = []
    prev = 0

    for c in cuts:
        parts.append(c - prev)   # guaranteed >= 1
        prev = c

    parts.append(N - prev)       # last part, also >= 1

    return parts


if __name__ == "__main__":
    N = 30
    M = 5

    parts = split_into_random_parts(N, M)

    print(f"Splitting N = {N} into M = {M} random parts:")
    print(" ".join(str(p) for p in parts))



"""
run:

Splitting N = 30 into M = 5 random parts:
3 9 10 3 5

"""

 



answered Jul 19 by avibootz

Related questions

...