0

I am trying to distribute a certain value over a random period of time. To clarify more ,

Suppose I want to distribute product x and y over 30 days. I have 1500 items of product x that has to be distributed over 30 days randomly. There is a restriction on the number of items that can be distributed over 1 day i.e.max 60.

I have been trying to scratch out something but am really unsucessful with this problem. I am really new to programming so it would be a real help if somebody could point me to the right approach.

As an addendum, if I have more than 1 items to be distributed (like suppose there are x,y and z) with different values (ex. 1500, 1000, 900) and there is a limitation on how many items can be distributed on a particular day (max 150 per day) will this logic still work or should I look at something new. Also, should there be a check, like suppose 100 of x, 20 of y and 30 of z are distributed, then subtract the value (for the next day I have 1400 of x, 980 of y and 870 of z available for distribution) as this will change the permutation values ?

Thank you guys !

Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
user257123
  • 11
  • 1
  • What did you scratch out? Where did you get stuck? Best practice is to explain your own efforts in your question. – A. Donda Oct 30 '13 at 16:59
  • There's lot of stuff remaining unclear... E.g. how random things should really be. You could throw 30 random numbers between zero and 60 and stop in case their sum exceeds 1500. If that sounds like a good start, check `randi` in MATLAB. But maybe 60 a day shouldn't come with the same probability as 1 per day... – sebastian Oct 30 '13 at 17:07
  • "Random" is too vague a term. You need to specify the desired _distribution_ of your numbers – Luis Mendo Oct 30 '13 at 22:34

2 Answers2

0

This should work for you!

days = 30;
elem = 1500;
max_x = 60; 

x = randi(max_x,days,1);
remain = elem - sum(x);

while remain > 0
   idx_1 = find(x < max_x);  % Numbers that can be increased
   idx_fill = randperm(numel(idx_1),remain);
   % idx_fill = idx_fill(:,1);    % Might be needed
   x(idx_1(idx_fill)) = x(idx_1(idx_fill)) + 1;
   remain = elem - sum(x);
end

while remain < 0
   idx_2 = find(x > 0);      % Numbers that can be reduced
   idx_red = randperm(numel(idx_2),abs(remain));
   % idx_red = idx_red(:,1);      % Might be needed
   x(idx_2(idx_red)) = x(idx_2(idx_red)) - 1;
   remain = elem - sum(x);
end

sum(x)
max(x)
min(x)

ans =  1500
ans =  60
ans =  34
Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70
0

This is an intuitive approach and works nicely for 2D arrays, without "randperm":

N = 36000;    % for three hundred years
days = 30;    % days
elem = 1500;    % elements in ten years
min_x = 0;    % daily minimum
max_x = 60;    % daily maximum
tic
x = zeros(days, N);
for hh = 1:elem
  % Add new candidates
  inds = randi(days, N, 1);
  inds = ((1:N).' - 1) * days + inds;
  x(inds) = x(inds) + 1;
  % Check
  inds_chck = x > max_x;
  any_inds_chck = any(inds_chck);
  find_any_inds_chck = find(any_inds_chck);
  ctrl = numel(find_any_inds_chck);
  while ctrl>0
    % First remove baddies
    inds = inds(find_any_inds_chck);
    x(inds) = x(inds) - 1;
    % Then reassign to new candidates
    inds = randi(days, ctrl, 1);
    inds = (find_any_inds_chck.' - 1) * days + inds;
    x(inds) = x(inds) + 1;
    % Check again
    inds_chck = x(:, find_any_inds_chck) > max_x;
    any_inds_chck = any(inds_chck);
    find_any_inds_chck = find(any_inds_chck);
    ctrl = numel(find_any_inds_chck);
  end
end
toc

But the price is a weird probability function:

hist(x(:), max_x - min_x + 1)

Note that the constraint has an obvious effect on the degrees of freedom as well.

Also note that they have tried to answer a similar question in Generate a random number with max, min and mean (average) in Matlab .

Community
  • 1
  • 1