I have a vector that contains several sequences with an increment of one, e.g.
in = [1:5 8:14 16:20 23:40]
For each of this sequences I would like to extract the start- and the endpoint of the sequence, i.e for above example I would get
out = [1 5; 8 14; 16 20; 23 40]
Of course, this can be done with a combination of for-loops and if-conditions, but that would not be very efficient and readable. Is there any more matlab-ish way to achieve this?
You can use diff to find where the runs stop and start and then use the resulting logical array (and a circularly shifted version of the logical array) to index into in to yield out
% Create a logical array that is TRUE at the beginning of each new run
starts = [true, diff(in) ~= 1];
% 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
% Use that array to index into IN and shift it to index into IN again
out = [in(starts); in(circshift(starts, [0 -1]))].';
% 1 5
% 8 14
% 16 20
% 23 40
Related
I don't find a solution to this problem
In my initialization I define an array "R" with certain number of values (the boolean flag with have the same length too). Later in my code I do an addition with a boolean flag.
Do you have an idea how to "update" this addition without editing it manually?
The part of the code i want to improve is
( (R(5)*B(i,5))+ (R(1)*B(i,1)) + (R(3)*B(i,3)) +(R(4)*B(i,4)) +(R(2)*B(i,2)) )
Thank you in advance for you answear
the code :
% i reflects the time
% bollean flag type double
B(1,:)=[0 0 0 0 0];
B(2,:)=[0 0 0 0 0];
B(3,:)=[0 0 0 0 1];
B(4,:)=[0 0 0 1 0];
B(5,:)=[0 0 0 1 1];
%info1
E(1)=0;
E(2)=0;
E(3)=10;
E(4)=20;
E(5)=40;
%info2
R = [1/30 1/30 1/30 1/30 1/30];
for i=1:5
for k=1:5
if E(i)>0
powerload_R2(i,k)= ( ( R(k))/( (R(5)*B(i,5))+ (R(1)*B(i,1)) + (R(3)*B(i,3)) +(R(4)*B(i,4)) +(R(2)*B(i,2)) ) ) *B(i,k)*E(i)+0; % fonctionnel
else
powerload_R2(i,k)= 0;
end
end
end
'end'
results
%results
powerload_R2(i,k)=
0 0 0 0 0
0 0 0 0 0
0 0 0 0 10
0 0 0 20 0
0 0 0 20 20
Your code could be greatly simplified. As #AnderBiguri has mentioned, this long line (R(5)*B(i,5))+ (R(1)*B(i,1)) + (R(3)*B(i,3)) +(R(4)*B(i,4)) +(R(2)*B(i,2)) is just the sum of the product of R elements with the corresponding elements of the ith row of B, or simply dot(R,B(i,:)).
Also you can initialize powerload_R2 = zeros(5) and alter only those rows corresponding to E > 0. This way, you only have to iterate find(E > 0) times over the rows of powerload_R2 and you don't need the inner k loop. That said, loops are not as evil these days as they used to be on the early years of MATLAB, so use the most natural way to write your algorithm before thinking about vectorization for speed.
% i reflects the time
% boolean flag type double
B = [0 0 0 0 0
0 0 0 0 0
0 0 0 0 1
0 0 0 1 0
0 0 0 1 1];
% info1
E = [0 0 10 20 40];
% info2
R(1:5) = 1/30;
powerload_R2 = zeros(5);
for i = find(E > 0)
powerload_R2(i,:) = R ./ dot(R,B(i,:)) .* B(i,:)*E(i); % fonctionnel
end
I have a logical vector in which I would like to iterate over every n-elements. If in any given window at least 50% are 1's, then I change every element to 1, else I keep as is and move to the next window. For example.
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
output = func(input,4);
output = [0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1];
This function is trivial to implement but is it possible to apply a vectorized implementation using logical indexing?. I am trying to build up the intuition of applying this technique.
here's a one liner (that works for your input):
func = #(input,n) input | kron(sum(reshape(input ,n,[]))>=n/2,ones(1,n));
of course, there are cases to solve that this doesnt answer, what if the size of the input is not commensurate in n? etc...
i'm not sure if that's what you meant by vectorization, and I didnt benchmark it vs a for loop...
Here is one way of doing it. Once understood you can compact it in less lines but I'll details the intermediate steps for the sake of clarity.
%% The inputs
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
1) Split your input into blocks of size n (note that your final function will have to check that the number of elements in input is a integer multiple of n)
c = reshape(input,n,[]) ;
Gives you a matrix with your blocks organized in columns:
c =
0 0 0 0 0
0 1 0 1 0
0 1 0 0 0
1 0 1 1 1
2) Perform your test condition on each of the block. For this we'll take advantage that Matlab is working column wise for the sum function:
>> cr = sum(c) >= (n/2)
cr =
0 1 0 1 0
Now you have a logical vector cr containing as many elements as initial blocks. Each value is the result of the test condition over the block. The 0 blocks will be left unchanged, the 1 blocks will be forced to value 1.
3) Force 1 columns/block to value 1:
>> c(:,cr) = 1
c =
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
1 1 1 1 1
4) Now all is left is to unfold your matrix. You can do it several ways:
res = c(:) ; %% will give you a column vector
OR
>> res = reshape(c,1,[]) %% will give you a line vector
res =
0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1
I have the following matrix:
M =[ 0 0 0 0 0 0 0 0 ;
0 0 0 0 0 0 6 0 ;
0 0 0 0 3 0 3 3 ;
0 0 0 9 9 6 9 6 ;
0 0 0 9 6 9 9 0 ;
0 0 0 0 6 3 0 0 ;
0 0 0 0 0 0 0 0 ;
0 0 0 0 0 0 0 0 ];
and I want to add 1 in ten randomly chosen elements of M which are greater than 0.
How to do this?
Find the indices of the elements greater than zero and generate n random samples from those indices which will be incremented. Then simply add 1 to the elements at those n random indexes.
n=10; %No. of elements of M greater than zero which will be incremented by 1
t1 = find(M>0); %Finding indices of elements of M which are greater than zero
t2 = randperm(length(t1)); %Generating random indices from which first n will be selected
M(t1(t2(1:n))) = M(t1(t2(1:n)))+1 %Incrementing elements of random n indices
If you have Statistics and Machine Learning Toolbox, you can use the following simpler
solution using randsample:
n=10;
temp = randsample(find(M>0),n);
M(temp) = M(temp)+1
You can select which elements to increment by creating a random permutation of the positions of the non-zero elements.
m = 10; % we want to increment 10 elements
elements = find(M); % positions of the nonzero elements
rand_order = randperm(numel(elements), m); % generate random permutation
M(elements(rand_order)) = M(elements(rand_order)) + 1;
randperm ensures that each nonzero element will only be selected once, in a random order.
I have arrays that stores only binary numbers like the below, binaries are of the size 1x31. Now I want to make the last bit the first and the first bit the last and so on. The choice of data structure is probably very poor here -- when I learn to play with binaries I probably get rid of the array. The binaries make the ordering of the arrays far easier with a simple sort. Anyway this is puzzle now:
Is there some ready command in Matlab for changing desceding binary to asceding binary?
Input
>> C(21,:)
ans =
(1,11) 1
(1,16) 1
(1,17) 1
>> full(C(21,:))
ans =
Columns 1 through 11
0 0 0 0 0 0 0 0 0 0 1
Columns 12 through 22
0 0 0 0 1 1 0 0 0 0 0
Columns 23 through 31
0 0 0 0 0 0 0 0 0
Goal for the output with some command such as invertDec2Asc
>> invertDec2Asc(C(21,:))
ans =
(1,21) 1
(1,16) 1
(1,15) 1
Try using num2str followed by fliplr
revnum = fliplr( num2str(num) )
Test
num = ['101010';'010101']
revnum = fliplr( num2str(num) )
num =
101010
010101
revnum =
010101
101010
flipud or fliplr is what you're looking for.
Matlab documentation
fliplr([1 0 1 0]) = [0 1 0 1]
fliplr('1010') = '0101'
format of binaries in matlab: '1010', e.g. created with dec2bin(10)
Given a matrix where 1 is the current subset
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
Is there a function, or quick method to get change the subset to the boundary of the current subset?
Eg. Get this subset from 'test' above
test =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 0
0 1 1 1 1 0
0 0 0 0 0 0
In the end I just want to get the minimum of the cells surrounding a subset of a matrix. Sure I could loop through and get the minimum of the boundary (cell by cell), but there must be a way to do it with the method i've shown above.
Note the subset WILL be connected, but may not be rectangular. This may be the big catch.
This is a possible subset.... (Would pad this with a NaN border)
test =
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1
Ideas?
The basic steps I'd use are:
Perform a dilation on the shape to get a new area which is the shape plus its boundary
Subtract the original shape from the dilated shape to leave just the boundary
Use the boundary to index your data matrix, then take the minimum.
Dilation
What I want to do here is pass a 3x3 window over each cell and take the maximum value in that window:
[m, n] = size(A); % assuming A is your original shape matrix
APadded = zeros(m + 2, n + 2);
APadded(2:end-1, 2:end-1) = A; % pad A with zeroes on each side
ADilated = zeros(m + 2, n + 2); % this will hold the dilated shape.
for i = 1:m
for j = 1:n
mask = zeros(size(APadded));
mask(i:i+2, j:j+2) = 1; % this places a 3x3 square of 1's around (i, j)
ADilated(i + 1, j + 1) = max(APadded(mask));
end
end
Shape subtraction
This is basically a logical AND and a logical NOT to remove the intersection:
ABoundary = ADilated & (~APadded);
At this stage you may want to remove the border we added to do the dilation, since we don't need it any more.
ABoundary = ABoundary(2:end-1, 2:end-1);
Find the minimum data point along the boundary
We can use our logical boundary to index the original data into a vector, then just take the minimum of that vector.
dataMinimum = min(data(ABoundary));
You should look at this as morphology problem, not set theory. This can be solved pretty easily with imdilate() (requires the image package). You basically only need to subtract the image to its dilation with a 3x3 matrix of 1.
octave> test = logical ([0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 1 1
0 0 1 1 1 1]);
octave> imdilate (test, true (3)) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
It does not, however, pads with NaN. If you really want that, you could pad your original matrix with false, do the operation, and then check if there's any true values in the border.
Note that you don't have to use logical() in which case you'll have to use ones() instead of true(). But that takes more memory and has worse performance.
EDIT: since you are trying to do it without using any matlab toolbox, take a look at the source of imdilate() in Octave. For the case of logical matrices (which is your case) it's a simple usage of filter2() which belongs to matlab core. That said, the following one line should work fine and be much faster
octave> (filter2 (true (3), test) > 0) - test
ans =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
One possible solution is to take the subset and add it to the original matrix, but ensure that each time you add it, you offset its position by +1 row, -1 row and +1 column, -1 column. The result will then be expanded by one row and column all around the original subset. You then use the original matrix to mask the original subet to zero.
Like this:
test_new = test + ...
[[test(2:end,2:end);zeros(1,size(test,1)-1)],zeros(size(test,1),1)] + ... %move subset up-left
[[zeros(1,size(test,1)-1);test(1:end-1,2:end)],zeros(size(test,1),1)] + ... %move down-left
[zeros(size(test,1),1),[test(2:end,1:end-1);zeros(1,size(test,1)-1)]] + ... %move subset up-right
[zeros(size(test,1),1),[zeros(1,size(test,1)-1);test(1:end-1,1:end-1)]]; %move subset down-right
test_masked = test_new.*~test; %mask with original matrix
result = test_masked;
result(result>1)=1; % ensure that there is only 1's, not 2, 3, etc.
The result for this on your test matrix is:
result =
0 0 0 0 0 0
0 1 1 1 1 0
0 1 0 0 1 0
0 1 0 0 1 1
0 1 0 0 0 0
0 1 0 0 0 0
Edited - it now grabs the corners as well, by moving the subset up and to the left, up and to the right, down then left and down then right.
I expect this would be a very quick way to achieve this - it doesn't have any loops, nor functions - just matrix operations.