I am new to Matlab and I am trying to create programmatically a square Matrix which may have some random stochastic columns but I can't come up with a working solution. By stochastic column I mean the sum of the column elements which are positive should be equal to 1 (the column non-zero elements should be the same and their sum equal to 1). The position of the non-zero elements is not important in the matrix. PS: some columns could be all-zero elements and some could be with only one non-zero element, in this case 1.
I need your guidance or an example of working code on this guys. Thanks in advance.
Here is an example:
A=
0.2500 0.5000 0 0 0 0 0
0.2500 0.5000 0.3333 0 0 0 0
0 0 0.3333 0.2500 0 0 0.3333
0.2500 0 0 0.2500 0 0.5000 0
0.2500 0 0 0.2500 0 0 0
0 0 0 0.2500 0 0.5000 0.3333
0 0 0.3333 0 0 0 0.3333
% here is my code but it's not doing the work yet
n = 5;
A = zeros(n, 5);
i = 0;
for i = 1:n
if rand < 0.5
i = i + 1;
A(i, :) = rand(1, 5);
end
end
A = A(1:i, :)
First generate a random floating point matrix and threshold as you have done. Once you threshold this, simply sum along each column, then divide every column by the sum. Broadcasting will be useful here so that you avoid having to loop through or replicate the summed values per column over all rows.
Something like this should work:
n = 7;
A = rand(n, n) >= 0.5;
sumA = sum(A, 1);
A = bsxfun(#rdivide, A, sumA);
% Or in MATLAB R2016b and up:
% A = A ./ sumA;
A(isnan(A)) = 0;
The first two lines are self-explanatory. Choose n, then create a n x n square matrix of random 0s and 1s. The third line finds the sum of each column, and the fourth line which is the pièce de resistance is taking the sum of each column and doing an internal replication so that you create a temporary matrix that is the same size as the random matrix, but each column contains the total sum for that column. You then divide element wise and that produces your result. This is achieved with the bsxfun function. The last line of code is very important. Supposing that you have a column where there are no 1s. This means that when it's time to normalize, we will encounter a 0 / 0 error which translates to NaN. The last line of code finds any values that are NaN and sets them to 0.
Alternatively in MATLAB R2016b and up, you can simply do the element-wise division operator ./ and it does the broadcasting already.
Example Run
After running the above code, this is one potential result:
>> A
A =
0.2500 0.5000 0 0.2500 0 0 0
0 0 0.2500 0.2500 1.0000 0 0
0 0 0 0.2500 0 0.2500 0.3333
0.2500 0 0 0.2500 0 0.2500 0
0.2500 0.5000 0.2500 0 0 0.2500 0
0 0 0.2500 0 0 0.2500 0.3333
0.2500 0 0.2500 0 0 0 0.3333
What about all zero columns?
To ensure that the code works for all zero columns, simply make the threshold when you create the random matrix more aggressive. Make it higher, like 0.8 or so. This means that there's a higher chance that you will get a 0 than a 1.
Therefore, I changed the second line of code to:
A = rand(n, n) >= 0.8;
When I did this and ran the code again, this is what I get for one run:
>> A
A =
0 0 0 0.2500 0 0.5000 0
0 0.5000 1.0000 0.2500 0 0.5000 0
0 0 0 0 1.0000 0 1.0000
0 0.5000 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0.2500 0 0 0
0 0 0 0.2500 0 0 0
Related
I'm trying to solve a system of 10 linear equations out of which the middle 8 equations look alike. They look like this :
t_i-1 - 2.3086*(t_i) + t_i+1 == -7.7160
where i = 2:9
so I decided to construct the coefficient matrix and the constant matrix(array) for the system of equations through looping.This is what I did.
T = sym('t' , [1 10]); %% Creates a vector T = [ t1 t2 .... t10]
A_10 = zeros(10,10);
b_10 = zeros(10,1);
for i = 2:9 %% This loop generates the equations and arranges them in the matrices A_10 and B_10.
T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(ans)
end
Everything except for the ninth row(last but one) is correct in the Matrix A_10. This is what A_10 looks like
A_10 =
Columns 1 through 9
0 0 0 0 0 0 0 0 0
1.0000 -2.3086 1.0000 0 0 0 0 0 0
0 1.0000 -2.3086 1.0000 0 0 0 0 0
0 0 1.0000 -2.3086 1.0000 0 0 0 0
0 0 0 1.0000 -2.3086 1.0000 0 0 0
0 0 0 0 1.0000 -2.3086 1.0000 0 0
0 0 0 0 0 1.0000 -2.3086 1.0000 0
0 0 0 0 0 0 1.0000 -2.3086 1.0000
0 0 0 0 0 0 0 1.0000 1.0000
0 0 0 0 0 0 0 0 0
Column 10
0
0
0
0
0
0
0
0
-2.3086
0
The last three elements of the row nine should be 1 , -2.3086 , 1 like the previous rows but it shows 1, 1, -2.3086. What am I doing wrong here?
This is what the iteration looks like in the loop
ans = t8 - (11543*t9)/5000 + t10 == -1929/250
The equation is correct too. I can't figure out what the problem is.
Without the second input vars, equationsToMatrix uses symvar to determine the variable list.
Using symvar directly with the last equation gives
>> i = 9;symvar(T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160)
ans =
[ t10, t8, t9]
So for whatever reason, symvar produced the incorrect ordering for only the last equation (possibly because 1 < 9). To remedy the situation, pass your intended ordering using the second input
eqn = T(i-1) - 2.3086*T(i) + T(i+1) == -7.7160;
[A_10(i,i-1:i+1),b_10(i,1)] = equationsToMatrix(eqn,T(i-1:i+1));
You'll also noticed I assigned the equation to an explicit variable eqn. This is better practice than relying on ans.
Also, since you're producing a numeric array anyway, you can produce A without the Symbolic Toolbox in a number of ways. For example:
n = 10;
A = full(spdiags(ones(n,1)*[1,-2.3086,1],[-1,0,1],n,n));
A([1,end],:) = 0;
I just want to know how to set this up. Seems like I can min f'x with linprog but not when f'x - b.
f' = [0.2000 0.0100 0.0100 0 0.0200 0.0100;
1.5700 1.3600 0.1000 0.0500 0.1600 0.1000;
0.2500 2.2800 4.2200 2.5100 0.6000 0.3600;
0 0 1.1000 4.8600 6.3900 1.2800;
0 0 0 0 2.1400 6.3200;
0 0 0 0 0 7.6600]
b = [ 0.0230;
0.1106;
0.5086;
2.1678;
4.3263;
7.7430]
I want to solve for x to minimize f'x-b where x is all positive.
Thanks!
Well, apart from the fact that the f' assignment will throw an error in MATLAB, f'x-b=0 is the same as f'x=b. So you can solve it by typing f'\b.
So I used MATLAB's bwdist function to obtain the distance transform of a binary image. My question is, how do I transform a signed distance matrix back into a binary image?
D = bwdist(BW)
Specifically, is there a transform that can go back from BW -> D?
If D = bwdist(BW), how about BW0 = D<=0?
Consider the first example from the bwdist documentation:
bw = zeros(5,5); bw(2,2) = 1; bw(4,4) = 1
bw =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
[D,IDX] = bwdist(bw)
D =
1.4142 1.0000 1.4142 2.2361 3.1623
1.0000 0 1.0000 2.0000 2.2361
1.4142 1.0000 1.4142 1.0000 1.4142
2.2361 2.0000 1.0000 0 1.0000
3.1623 2.2361 1.4142 1.0000 1.4142
To get back your binary image, you just want the points in the distance transform that are equal to zero (i.e. on a non-zero pixel in the original bw):
>> bw0 = D<=0
bw0 =
0 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
>> isequal(bw,bw0)
ans =
1
I have the feeling I am missing something intuitive in my solution for generating a partially varied block-diagonal grid. In any case, I would like to get rid of the loop in my function (for the sake of challenge...)
Given tuples of parameters, number of intervals and percentage variation:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
The desired output should be:
pspacegrid(params,perc,nint)
ans =
90.0000 0.5000 1.0000
100.0000 0.5000 1.0000
110.0000 0.5000 1.0000
100.0000 0.4500 1.0000
100.0000 0.5000 1.0000
100.0000 0.5500 1.0000
100.0000 0.5000 0.9000
100.0000 0.5000 1.0000
100.0000 0.5000 1.1000
21.6000 1.0000 0.9000
24.0000 1.0000 0.9000
26.4000 1.0000 0.9000
24.0000 0.9000 0.9000
24.0000 1.0000 0.9000
24.0000 1.1000 0.9000
24.0000 1.0000 0.8100
24.0000 1.0000 0.9000
24.0000 1.0000 0.9900
where you can see that the variation occurs at the values expressed by this mask:
mask =
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
0 0 1
0 0 1
The function pspacegrid() is:
function out = pspacegrid(params, perc, nint)
% PSPACEGRID Generates a parameter space grid for sensitivity analysis
% Size and number of variation steps
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
% Mask to index positions where to place interpolated
[tmp{1:sz(2)}] = deal(true(nsteps,1));
mask = repmat(logical(blkdiag(tmp{:})),sz(1),1);
zi = cell(sz(1),1);
% LOOP per each parameter tuple
for r = 1:sz(1)
% Columns, rows, rows to interpolate and lower/upper parameter values
x = 1:sz(2);
y = [1; nint*2+1];
yi = (1:nint*2+1)';
z = [params(r,:)*(1-perc); params(r,:)*(1+perc)];
% Interpolated parameters
zi{r} = interp2(x,y,z, x, yi);
end
out(mask) = cat(1,zi{:});
I think I got it, building off your pre-loop code:
params = [100 0.5 1
24 1 0.9];
nint = 1;
perc = 0.1;
sz = size(params);
nsteps = nint*2+1;
% Preallocate output
out = reshape(permute(repmat(params,[1,1,nsteps*sz(2)]),[3,1,2]),[],sz(2));
%Map of the percentage moves
[tmp{1:sz(2)}] = deal(linspace(-perc,perc,nint*2+1)');
mask = repmat(blkdiag(tmp{:}),sz(1),1) + 1; %Add one so we can just multiply at the end
mask.*out
So instead of making your mask replicate the ones I made it replicate the percentage moves each element makes which is a repeating pattern, the basic element is made like this:
linspace(-perc,perc,nint*2+1)'
Then it's as simple as adding 1 to the whole thing and multiplying by your out matrix
I tested it as follows:
me = mask.*out;
you = pspacegrid(params, perc, nint);
check = me - you < 0.0001;
mean(check(:))
Seemed to work when I fiddled with the inputs. However I did get an error with your function, I had to change true(...) to ones(...). This might be because I'm running it online which probably uses Octave rather than Matlab.
I'm using Matlab and well it's straightforward to find the probability of an element in a matrix, but I a little unsure of how to find probability of an element in a row or column.
e.g this matrix:
X = [
1 2 4 1 8;
5 3 6 9 2;
6 2 2 3 2
];
How would I find the probability of "2" occurring in each row and column of this random matrix.
You could do the following:
X_unique = unique(X);
p_row = zeros(size(X,1),numel(X_unique));
p_col = zeros(size(X,2),numel(X_unique));
for ii = 1:size(X,1)
p_row(ii,:) = hist(X(ii,:),X_unique);
p_row(ii,:) = p_row(ii,:)/sum(p_row(ii,:));
end
for ii = 1:size(X,2)
p_col(ii,:) = hist(X(:,ii),X_unique);
p_col(ii,:) = p_col(ii,:)/sum(p_col(ii,:));
end
Now, each row of p_row contains the probability distribution of the elements of unique(X) in the corresponding row of X and each row of p_col contains the probability distribution of the elements of unique(X) in the corresponding column of X.
For example, for the given example,
X_unique =
1
2
3
4
5
6
8
9
Thus,
p_row =
0.4000 0.2000 0 0.2000 0 0 0.2000 0
0 0.2000 0.2000 0 0.2000 0.2000 0 0.2000
0 0.6000 0.2000 0 0 0.2000 0 0
p_col =
0.3333 0 0 0 0.3333 0.3333 0 0
0 0.6667 0.3333 0 0 0 0 0
0 0.3333 0 0.3333 0 0.3333 0 0
0.3333 0 0.3333 0 0 0 0 0.3333
0 0.6667 0 0 0 0 0.3333 0
Here's a simple, not-quite-Matlab-ish solution that works on non-empty bi-dimensional matrices, looking for elements with the value "2", and returning probabilities by column:
a = [1 2 4 1 8; 5 3 6 9 2; 6 2 2 3 2];
nrows = size(a,1);
ncols = size(a,2);
pc = zeros(1, ncols); % Prob. by column
% Iterate trough columns
for k = 1:ncols
n = sum(a(:,k) == 2);
pc(k) = n/nrows;
end;
You can adapt it to compute "probabilities" by row, or by other dimensions, or look for other values.