Hello, I want to generate a random matrix M * N, with two constraints: 1-the sum of the lines is fixed 2-the sum of the columns is fixed. for exmaple: matrix 6*4, sum of lines = 1 and the sum of the 4 columns respectively: 2.43 1.68 1.53 1.18 thank you in advance
MATLAB: Random matrix with constraints:
matrix arrayrandomvector
Related Solutions
This is not simple, if you want to find a truly uniform set. In 24 dimensions, things get fairly complicated. And the domain the numbers can live in is actually pretty wide, thus the interval [5,800].
So, if you have all numbers at or near their mininum,
5*24ans = 120>> 800*24ans = 19200>> (5 + 800)/2*24ans = 9660
The point being that it will be a quite rare event that 24 numbers, chosen randomly from that interval, will have a sum in the interval [3550,3650].
The law of large numbers tells us that the sum of that set will be effectively normally distributed. And, in fact, this gives us a solution to the problem!
Lets see. Each member of that set will be uniform, on the interval [5,800]. That means the mean of x_i will be
a = 5;b = 800;(a + b)/2ans = 402.5
And the variance (of each number in the set) will be
(b-a)^2/12ans = 52668.75
So now the sum of 24 of them will be fairly accurately normally distributed, with mean, variance, and standard deviation:
sumMean = (a+b)/2*24xmean = 9660sumVar = (b-a)^2/12*24xvar = 1264050sumStd = sqrt(sumVar)xstd = 1124.29978208661
So, now what are the odds that you will find a sum in the range from [3550,3650]? That would be found from a cumulative normal.
sumLimits = [3550,3650];normcdf(sumLimits,sumMean,sumStd)ans = 2.74761306010529e-08 4.50716095152589e-08 diff(ans)ans = 1.7595478914206e-08
Hmm. So you will probably need to generate roughly 1e8 sets of 24 uniform numbers before you find a single set that lives in the interval [3550,3650].
But! As I said, this actually gives you a near trivial solution! How? We break the problem down into two simpler problems. Hard problems are hard. Easy problems are way easier. So lets create two simpler problems.
First, can we sample from a truncated normal distributiuon? That part is easy.
norminv(sumNormProbLimits(1) + rand()*diff(sumNormProbLimits),sumMean,sumStd)ans = 3637.00633112408
As you can see, that is a number that has atuncated normal distribution, with the desired parameters. So now we can just use randfixedsum. I'll put it all together here:
a = 5;b = 800;ndim = 24;sumMean = (a+b)/2*ndim;sumVar = (b-a)^2/12*ndim;sumStd = sqrt(sumVar);sumLimits = [3550,3650];sumNormProbLimits = normcdf(sumLimits,sumMean,sumStd);S = norminv(sumNormProbLimits(1) + rand()*diff(sumNormProbLimits),sumMean,sumStd);randfixedsum(24,1,S,a,b)ans = 32.6666351919248 226.171574450247 26.4486244673284 59.5273902733376 105.140425145937 198.085619814426 313.588691531256 125.527412419838 222.108869160278 78.6355991625287 116.832965448386 25.2315920517267 10.7762636314948 295.321051677379 339.225232904641 91.7004913938697 29.5858150543207 184.827862803465 37.7525635267701 115.866539562388 512.657889835195 372.544944227602 13.6087483202661 58.868132270981
So, a set of 24 uniformly distributed random numbers that have their sum in the desired interval. The numbers really are uniformly distributed to lie in the interval [5,800], but the condition that the sum be so relatively small, makes it unlikely that any of them are near the maximum. On this random set, the max was as large as 512. That seems reasonable to me, under the conditional sampling that was required.
sum(ans)ans = 3592.70093432559
It was really pretty easy to do. I did need randfixedsum, which you can get from the File Exchange for free download.
Since you are minimizing the dot product, the thing to realize is that this is an integer linear programming problem. Following code apply intlinprog() function.
rng(0);M = rand(1000, 20); % distance matrix
[m, n] = size(M);row_sum = ones(m, 1);col_sum = [50 45 60 35 25 90 30 35 75 90 10 5 30 40 90 60 40 60 45 85];f = reshape(M', 1, []);x = repmat({ones(1, n)}, m, 1);Aeq = [blkdiag(x{:}); repmat(eye(n), 1, m)];Beq = [row_sum(:); col_sum(:)];lb = zeros(m*n, 1);ub = ones(m*n, 1);sol = intlinprog(f, 1:numel(x0), [], [], Aeq, Beq, lb, ub);sol = reshape(sol, n, []).';
If you have knowledge about integer linear programming, then the logic of this code is quite easy to follow. Let me know if there is some confusion.
Related Question
- Generating dispersed (non-integer) random matrix/array that sums to a particular value
- Matrix addition of a first column in a loop
- Sum of a 4D matrix
- Random sampling of elements from an array based on a target condition in MATLAB
- Help with this Matrix summation
- Random positive numbers with constant sum
- Error: Index in position 2 exceeds array bounds (must not exceed 2).
Best Answer