I’m wondering if there’s an algorithm to tell me how many results I’d get if I am looking for permutations within bounds.
I have a program that looks for combinations. The best way to explain is it vai an example, say you have 4 items you want to buy at a store: apple,peach,pear and orange. You want to know how much percent you can fit of each into a basket but you tell yourself you want a min. of 20 of each item and a max of 60 of each item(so apple:25, peach:25, pear:25, and orange:25 works perfectly but not apple:0, peach:0, pear:50, and orange:50 because we set a min of 25). If you ran this example, the correct number of items returned would be 1771.
Is there a way to calculate this in advance instead of running the actual program? I have a program that needs to do premuations and I’m trying to find the ideal mix, so I wanted to write a program that gives me the correct output then I’ll do a monte carlo simluation on the inputs to find the mixture of items/ranges I like.
Here’s the program I used(it works in my case when the top band is never used, but if the ranges are tigher, 1-4 then it doesn’t work because it gives me the combinations without considering the ranges):
import math
def nCr(n,r):
f = math.factorial
return f(n) / f(r) / f(n-r)
if __name__ == '__main__':
print nCr(20+4-1,20) #percent+buckets(items)-1, percent
this gives me the correct answer(1771) because it doesn’t need to factor in the max(60) because its never reached(it only uses 20 as the input). But is there a way I could modify this formula(or use something else) that would tell me how many results to expect if I have something like 40 items with a range of 2-5 or something(something that factors in the max value as well).
Is there an algorithm that can do what I’m looking for?
You can find the number with the inclusion-exclusion principle. Let
distributions(itemCount,bucketCount)be the number of unrestricted distributions ofitemCountitems tobucketCountbuckets. I disregard the lower limit because that’s dealt with simply by subtractingbucketCount*lowerLimititems.The number of ways to distribute
itemCountitems tobucketCountbuckets with each bucket containing at mostupperLimititems is the number of unrestricted distributions minus the number of unrestricted distributions where at least one bucket contains more thanupperLimititems. The latter can be calculated with the inclusion exclusion principle as follows:There are
bucketCountchoices of a bucket to contain at leastupperLimit+1items, there remainitemCount - (upperLimit+1)items to distribute tobucketCountbuckets:must be subtracted from the number of unrestricted distributions.
But we have subtracted the distributions where two buckets contain more than
upperLimititems twice, we must correct that and addagain, because there are
nCr(bucketCount,2)choices of the two buckets.But we have subtracted the distributions where three buckets contain more than
upperLimititems thrice, and added it again thrice (nCr(3,2)), so we have to subtractto rectify that. etc.
All in all, the number is
where
(since there is no way to distribute a negative number of items).
Corrected code from your gist with an implementation of the function to count the ways of distributing the items respecting lower and upper limits:
Note that for large numbers of items and buckets, calculating
nCrwith the factorial is not the best way, it leads to large intermediate results and uses more operations than necessary.