Matlab How to assign values on non-diagonal matrix - matlab

I have a matrix called "C" with 5x5 dimension, and i want to put 3 formulas (first formula where I have 0 (on diagonal, the second one where I have 1 and the third one where I have 2)
0 1 1 1 1
2 0 1 1 1
2 2 0 1 1
2 2 2 0 1
2 2 2 2 0
The above notation is just to know where I want to put the formula.
For diagonal it works with:
C(logical(eye(size(C)))) = V
where V is my formula.

Related

Create a matrix in MATLAB with limited number of elements

I would like to create an 12*3 matrix in MATLAB that has only 2 non-zero elements in each row. How should I generate a code to get all the possible conditions. The non-zero elements can take on any integers from 1 to 2.
If you want all the possible combination without repetition for 0 and with repetition for 1 and 2:
% Number of integer with repetition.
n = 2
% Generate all the possible combination of 1 and 2.
[x1,x2] = meshgrid(1:n,1:n);
M = [zeros(n^2,1),x1(:),x2(:)];
% We shift the 0 column n time.
M = cell2mat(arrayfun(#(x) circshift(M,x,2),0:n,'UniformOutput',0).');
Result:
M =
0 1 1
0 1 2
0 2 1
0 2 2
1 0 1
2 0 1
1 0 2
2 0 2
1 1 0
1 2 0
2 1 0
2 2 0

Count the first x integers of a group of values

I want to get the count starting from 1, of the number of occurrences of Y until its subsequent value is N. A simple example table can be found below, I've added an additional column called expected output to highlight what I'm trying to achieve.
tab:([]x:`N`N`Y`N`N`Y`Y`Y`N`N`Y`Y`Y;expected_output:0 0 1 0 0 1 2 3 0 0 1 2 3)
I have been playing around with the idea of trying to use cut (granted that I can find the correct indexes) I could split the table up, get the count of each list, then piece it all back together somehow e.g.
0 2 3 5 8 10 cut tab
Approach without scan, not as neat as terry's but should be faster on larger tab.
q)update o:{a+r-maxs differ[x]*r:sums a:`Y=x}x from tab
x expected_output o
-------------------
N 0 0
N 0 0
Y 1 1
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
One approach using scan
q)update c:0{y*x+y}\x=`Y from tab
x expected_output c
-------------------
N 0 0
N 0 0
Y 1 1
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
Essentially a modified version of sums which resets the counter back to zero (using zero/false multiplication) whenever the next boolean is zero

Calculate mean of all values below the diagnonal line in an adjacency matrix

I have an adjacency matrix M, something like this:
[1 2 0 2 4
2 1 2 0 -1
0 3 1 2 3
2 0 2 1 0
4 -1 3 0 1]
I want to calculate the mean of all values below (but not including) the diagonal. The final output should be 1.5.
To get those values, I thought I'd use N = tril(M,-1). The issue is that I now have zeros in upper and lower part of the matrix N and therefore mean(sum(N)./sum(N~=0)) wouldn't work. Since I also have negative values, I can't just do the mean of values >=0 either. How can I do this?
In one line using logical indexing to extract just the values below the diagonal:
M = [ 1 2 0 2 4;
2 1 2 0 -1;
0 3 1 2 3;
2 0 2 1 0;
4 -1 3 0 1];
mean(M(tril(true(size(M)),-1)))
This returns 1.5 as #excaza indicated.

MATLAB generate all ways that n items can be put into m bins?

I want to find all ways that n items can be split among m bins. For example, for n=3 and m=3 the output would be (the order doesn't matter):
[3 0 0
0 3 0
0 0 3
2 1 0
1 2 0
0 1 2
0 2 1
1 0 2
2 0 1
1 1 1]
The algorithm should be as efficient as possible, preferrably vectorized/using inbuilt functions rather than for loops. Thank you!
This should be pretty efficient.
It works by generating all posible splitings of the real interval [0, n] at m−1 integer-valued, possibly coincident split points. The lengths of the resulting subintervals give the solution.
For example, for n=4 and m=3, some of the possible ways to split the interval [0, 4] at m−1 points are:
Split at 0, 0: this gives subintervals of lenghts 0, 0, 4.
Split at 0, 1: this gives subintervals of lenghts 0, 1, 3.
...
Split at 4, 4: this gives subintervals of lenghts 4, 0, 0.
Code:
n = 4; % number of items
m = 3; % number of bins
x = bsxfun(#minus, nchoosek(0:n+m-2,m-1), 0:m-2); % split points
x = [zeros(size(x,1),1) x n*ones(size(x,1),1)]; % add start and end of interval [0, n]
result = diff(x.').'; % compute subinterval lengths
The result is in lexicographical order.
As an example, for n = 4 items in m = 3 bins the output is
result =
0 0 4
0 1 3
0 2 2
0 3 1
0 4 0
1 0 3
1 1 2
1 2 1
1 3 0
2 0 2
2 1 1
2 2 0
3 0 1
3 1 0
4 0 0
I'd like to suggest a solution based on an external function and accumarray (it should work starting R2015a because of repelem):
n = uint8(4); % number of items
m = uint8(3); % number of bins
whichBin = VChooseKR(1:m,n).'; % see FEX link below. Transpose saves us a `reshape()` later.
result = accumarray([repelem(1:size(whichBin,2),n).' whichBin(:)],1);
Where VChooseKR(V,K) creates a matrix whose rows are all combinations created by choosing K elements of the vector V with repetitions.
Explanation:
The output of VChooseKR(1:m,n) for m=3 and n=4 is:
1 1 1 1
1 1 1 2
1 1 1 3
1 1 2 2
1 1 2 3
1 1 3 3
1 2 2 2
1 2 2 3
1 2 3 3
1 3 3 3
2 2 2 2
2 2 2 3
2 2 3 3
2 3 3 3
3 3 3 3
All we need to do now is "histcount" the numbers on each row using positive integer bins to get the desired result. The first output row would be [4 0 0] because all 4 elements go in the 1st bin. The second row would be [3 1 0] because 3 elements go in the 1st bin and 1 in the 2nd, etc.

Transform a matrix to a stacked vector where all zeroes after the last non-zero value per row are removed

I have a matrix with some zero values I want to erase.
a=[ 1 2 3 0 0; 1 0 1 3 2; 0 1 2 5 0]
>>a =
1 2 3 0 0
1 0 1 3 2
0 1 2 5 0
However, I want to erase only the ones after the last non-zero value of each line.
This means that I want to retain 1 2 3 from the first line, 1 0 1 3 2 from the second and 0 1 2 5 from the third.
I want to then store the remaining values in a vector. In the case of the example this would result in the vector
b=[1 2 3 1 0 1 3 2 0 1 2 5]
The only way I figured out involves a for loop that I would like to avoid:
b=[];
for ii=1:size(a,1)
l=max(find(a(ii,:)));
b=[b a(ii,1:l)];
end
Is there a way to vectorize this code?
There are many possible ways to do this, here is my approach:
arotate = a' %//rotate the matrix a by 90 degrees
b=flipud(arotate) %//flips the matrix up and down
c= flipud(cumsum(b,1)) %//cumulative sum the matrix rows -and then flip it back.
arotate(c==0)=[]
arotate =
1 2 3 1 0 1 3 2 0 1 2 5
=========================EDIT=====================
just realized cumsum can have direction parameter so this should do:
arotate = a'
b = cumsum(arotate,1,'reverse')
arotate(b==0)=[]
This direction parameter was not available on my 2010b version, but should be there for you if you are using 2013a or above.
Here's an approach using bsxfun's masking capability -
M = size(a,2); %// Save size parameter
at = a.'; %// Transpose input array, to be used for masked extraction
%// Index IDs of last non-zero for each row when looking from right side
[~,idx] = max(fliplr(a~=0),[],2);
%// Create a mask of elements that are to be picked up in a
%// transposed version of the input array using BSXFUN's broadcasting
out = at(bsxfun(#le,(1:M)',M+1-idx'))
Sample run (to showcase mask usage) -
>> a
a =
1 2 3 0 0
1 0 1 3 2
0 1 2 5 0
>> M = size(a,2);
>> at = a.';
>> [~,idx] = max(fliplr(a~=0),[],2);
>> bsxfun(#le,(1:M)',M+1-idx') %// mask to be used on transposed version
ans =
1 1 1
1 1 1
1 1 1
0 1 1
0 1 0
>> at(bsxfun(#le,(1:M)',M+1-idx')).'
ans =
1 2 3 1 0 1 3 2 0 1 2 5