How to count maximum number of recurring elements? [duplicate] - matlab

This question already has answers here:
Series of consecutive numbers (different lengths)
(3 answers)
Closed 8 years ago.
Grid_outage(:,1) = 1;
Grid_outage(:,2) = 1;
Grid_outage(:,3) = 1;
Grid_outage(:,4) = 0;
Grid_outage(:,5) = 0;
Grid_outage(:,6) = 0;
Grid_outage(:,7) = 0;
Grid_outage(:,8) = 0;
Grid_outage(:,9) = 0;
Grid_outage(:,10) = 0;
Grid_outage(:,11) = 0;
Grid_outage(:,12) = 1;
Grid_outage(:,13) = 0;
Grid_outage(:,14) = 1;
Grid_outage(:,15) = 0;
Grid_outage(:,16) = 0;
Grid_outage(:,17) = 1;
Grid_outage(:,18) = 0;
Grid_outage(:,19) = 1;
Grid_outage(:,20) = 0;
Grid_outage(:,21) = 0;
Grid_outage(:,22) = 0;
Grid_outage(:,23) = 1;
Grid_outage(:,24) = 0;
I would like to count the maximum number of Zeros that occur in a sequence, for e.g. I would like that above result be 8 which shows the maximum number of zeros that occur together, rather than the total number of zeros which is 16.
How do I code that in matlab

For the purpose of transparency a very simple algoritm.
Assume you can put your sequence in a vector X:
% Create X containing some zeros.
X = round(rand(30,1));
% Use a counter to count the number of sequential zeros.
count = 0;
% Use a variable to keep the maximum.
max_count = 0;
% Loop over every element
for ii=1:length(X);
% If a zero is encountered increase the counter
if(X(ii)==0)
count=count+1;
% If no zero is encountered check if the number of zeros in the last sequence was largest.
elseif count>max_count
max_count=count;
count=0;
% Else just reset the counter
else
count=0;
end
end
% Check if the last number of the vector exceeded the largest sequence.
if(count>max_count)
max_count=count;
end
EDIT: Dan's solution is more efficient starting from approximately ~200 elements.

max(diff(find(diff(Grid_outage))))
Find where a sequence of consecutive numbers changes using diff
Get the actual index numbers of where this happens using find
Use diff again to count the number of elements between each "transition"
Finally call max to get the largest sequence of consecutive numbers.
Note that you might have trouble if the largest sequence occurs at the edges, in this case I suggest that you first prepend and append an inverted bit to your matrix like this: [1-Grid_outage(1), Grid_outage, 1-Grid_outage(end)];

In order to find how many times the parameter x occurs together in a sequence, you can use:
if a(:) == x
result = length(a); % Whole vector has the x parameter
else
result = max(find(a~=x,1,'first') - 1, length(a) - find(a~=x,1,'last')); % Maximum difference in the edge
if ~isempty(max(diff(find(a~=x))) - 1)
if isempty(result)
result = max(diff(find(a~=x))) - 1; % Maximum difference in the body
elseif result < max(diff(find(a~=x))) - 1
result = max(diff(find(a~=x))) - 1; % Maximum difference in the body
end;
end;
end;

Related

Output 1, 0.5, or 0 depending if a matrix elements are prime, 1, or neither

I am sending a matrix to my function modifikuj, where I want to replace the elements of the matrix with:
1 if element is a prime number
0 if element is a composite number
0.5 if element is 1
I dont understand why it is not working. I just started with MATLAB, and I created this function:
function B = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j))
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
With
A = [1,2;3,4];
D = modifikuj(A);
D should be:
D=[0.5, 1; 1 0];
In MATLAB you'll find you can often avoid loops, and there's plenty of built in functions to ease your path. Unless this is a coding exercise where you have to use a prescribed method, I'd do the following one-liner to get your desired result:
D = isprime( A ) + 0.5*( A == 1 );
This relies on two simple tests:
isprime( A ) % 1 if prime, 0 if not prime
A == 1 % 1 if == 1, 0 otherwise
Multiplying the 2nd test by 0.5 gives your desired condition for when the value is 1, since it will also return 0 for the isprime test.
You are not returning anything from the function. The return value is supposed to be 'B' according to your code but this is not set. Change it to A.
You are looping k until A(i,j) which is always divisible by itself, loop to A(i,j)-1
With the code below I get [0.5,1;1,0].
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
prost=1;
if (A(i,j) == 1)
A(i,j) = 0.5;
else
for k = 2:(A(i,j)-1)
if(mod(A(i,j),k) == 0)
prost=0;
end
end
if(prost==1)
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
In addition to #EuanSmith's answer. You can also use the in built matlab function in order to determine if a number is prime or not.
The following code will give you the desired output:
A = [1,2;3,4];
A(A==1) = 0.5; %replace 1 number with 0.5
A(isprime(A)) = 1; %replace prime number with 1
A(~ismember(A,[0.5,1])) = 0; %replace composite number with 0
I've made the assumption that the matrice contains only integer.
If you only want to learn, you can also preserve the for loop with some improvement since the function mod can take more than 1 divisor as input:
function A = modifikuj(A)
[n,m] = size(A);
for i = 1:n
for j = 1:m
k = A(i,j);
if (k == 1)
A(i,j) = 0.5;
else
if all(mod(k,2:k-1)) %check each modulo at the same time.
A(i,j)=1;
else
A(i,j)=0;
end
end
end
end
And you can still improve the prime detection:
2 is the only even number to test.
number bigger than A(i,j)/2 are useless
so instead of all(mod(k,2:k-1)) you can use all(mod(k,[2,3:2:k/2]))
Note also that the function isprime is a way more efficient primality test since it use the probabilistic Miller-Rabin algorithme.

MATLAB — How to eliminate equal matrices that are created randomly inside loop?

The code segment I'm working on is given below:
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
i = 1;
while i <= 10 %number of iterations
ind = randi([1 NphaseSteps],10,10);
inField{i} = phases(ind);
save('inField.mat', 'inField')
i = i + 1;
end
Now, what I want is to keep track of these randomly created matrices "inField{i}" and eliminate the ones that are equal to each other. I know that I can use "if" condition but since I'm new to programming I don't know how to use it more efficiently so that it doesn't take too much time. So, I need your help for a fast working program that does the job. Thanks in advance.
My actual code segment (after making the changes suggested by #bisherbas) is the following. Note that I actually want to use the variable "inField" inside the loop for every random created matrix and the loop advances only if the result satisfies a specific condition. So, I think the answer given by #bisherbas doesn't really eliminate the equal inField matrices before they are used in the calculation. This is, of course, my fault since I didn't declare that in the beginning.
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
nIterations = 5;
inField = cell(1,nIterations);
i = 1;
j = 1;
while i <= nIterations % number of iterations
ind = randi([1 NphaseSteps],TMsize,TMsize);
tmp = phases(ind);
idx = cellfun(#(x) isequal(x,tmp),inField);
if ~any(idx)
inField{i} = tmp;
end
j = j+1;
outField{i} = TM * inField{i};
outI = abs(outField{i}).^2;
targetIafter{i} = abs(outField{i}(focusX,focusY)).^2;
middleI = targetIafter{i} / 2;
if (max(max(outI)) == targetIafter{i})...
&& ( sum(sum((outI > middleI).*(outI < max(max(outI))))) == 0 )
save('inFieldA.mat', 'inField')
i = i + 1;
end
if mod(j-1,10^6) == 0
fprintf('The number of random matrices tried is: %d million \n',(j-1)/10^6)
end
end
Additionally, I've written a seemingly long expression for my loop condition:
if (max(max(outI)) == targetIafter{i})...
&& ( sum(sum((outI > middleI).*(outI < max(max(outI))))) == 0 )
save('inFieldA.mat', 'inField')
i = i + 1;
end
Here I want a maximum element at some point (focusX, focusY) in the outField matrix. So the first condition decides whether the focus point has the maximum element for the matrix. But I additionally want all other elements to be smaller than a specific number (middleI) and that's why the second part of the if condition is written. However, I'm not very comfortable with this second condition and I'm open to any helps.
Try this:
NphaseSteps = 6;
phases = exp( 2*pi*1i * (0:(NphaseSteps-1))/NphaseSteps );
i = 1;
inField = cell(1,NphaseSteps);
while i <= NphaseSteps %number of iterations
ind = randi([1 NphaseSteps],NphaseSteps,NphaseSteps);
tmp = phases(ind);
idx = cellfun(#(x) isequal(x,tmp),inField);
if ~any(idx)
inField{i} = tmp;
end
save('inField.mat', 'inField')
i = i + 1;
end
Read more on cellfun here:
https://www.mathworks.com/help/matlab/ref/cellfun.html

Looping through to find max value without using max()

I'm trying to iterate in MATLAB (not allowed to use in built functions) to find the maximum value of each row in a certain matrix. I've been able to find the max value of the whole matrix but am unsure about isolating the row and finding the max value (once again without using max()).
My loop currently looks like this:
for i = 1:size(A, 1)
for j = 1:size(A, 2)
if A(i, j) > matrix_max
matrix_max = A(i, j);
row = i;
column = j;
end
end
end
You need a vector of results, not a single value. Note you could initialise this to zero. Don't initialise to zero unless you know you only have positive values. Instead, initialise to -inf using -inf*ones(...), as all values are greater than negative infinity. Or (see the bottom code block) initialise to the first column of A.
% Set up results vector, same number of rows as A, start at negative infinity
rows_max = -inf*ones(size(A,1),1);
% Set up similar to track column number. No need to track row number as doing each row!
col_nums = zeros(size(A,1),1);
% Loop through. i and j = sqrt(-1) by default in MATLAB, use ii and jj instead
for ii = 1:size(A,1)
for jj = 1:size(A,2)
if A(ii,jj) > rows_max(ii)
rows_max(ii) = A(ii,jj);
col_nums(ii) = jj;
end
end
end
Note that if vectorisation doesn't violate your "no built-ins" rule (it should be fine, it's making the most of the MATLAB language), then you can remove the outer (row) loop
rows_max = -inf*ones(size(A,1),1);
col_nums = zeros(size(A,1),1);
for jj = 1:size(A,2)
% Get rows where current column is larger than current max stored in row_max
idx = A(:,jj) > rows_max;
% Store new max values
rows_max(idx) = A(idx,jj);
% Store new column indices
col_nums(idx) = jj;
end
Even better, you can cut your loop short by 1, and initialise to the first column of A.
rows_max = A(:,1); % Set current max to the first column
col_nums = ones(size(A,1),1); % ditto
% Loop from 2nd column now that we've already used the first column
for jj = 2:size(A,2)
idx = A(:,jj) > rows_max;
rows_max(idx) = A(idx,jj);
col_nums(idx) = jj;
end
You can modified it likes the following to get each max for each row:
% initialize
matrix_max = zeros(size(A,1),1);
columns = zeros(size(A,1),1);
% find max
for i = 1:size(A, 1)
matrix_max(i) = A(i,1);
columns(i) = 1;
for j = 2:size(A, 2)
if A(i, j) > matrix_max(i)
matrix_max(i) = A(i, j);
columns(i) = j;
end
end
end

Produce set of random integers with minimum intervals in Matlab

I would like to randomly produce a set of integers ranging from 1~100. After sorting the integers, the minimum interval between each integer should not be less than a 2. For example
2,4,8,10
satisfies the requirement while the following set
2,4,5,7
does not since the interval between 4 and 5 is less than 2.
Is there any way to achieve this? Thanks!
N = 10; % number of integers required
delta = 2; % minimum difference required
a = randperm(100);
idx = 1;
b = a(idx);
while(length(b) < N && idx < length(a))
idx = idx+1;
c = abs(b - a(idx));
if any(c < delta)
continue;
end
b = [b; a(idx)];
end
b

Traverse matrix in segments

I have a huge waveform matrix:
[w,fs] = wavread('file.wav');
length(w)
ans =
258048
I want to go through this matrix in segments (say 50) and get the maximum of these segments to compare it to another value. I tried this:
thold = max(w) * .04;
nwindows = 50;
left = 1;
right = length(w)/nwindows;
counter = 0;
for i = 1:nwindows
temp = w(left:right);
if (max(temp) > thold)
counter = counter + 1;
end
left = right;
right = right+right;
end
But MATLAB threw tons of warnings and gave me this error:
Index exceeds matrix dimensions.
Error in wlengthdur (line 17)
temp = w(left:right);
Am I close or way off course?
An alternative approach would be to use reshaped to arrange you vector in to a 2D matrix with number of row n and columns equal to ceil(length(w) / n) i.e. round up so that it is divisible as matlab matrices must be rectangular. This way you can find the max or whatever you need in one step without looping.
w = randn(47, 1);
%this needs to be a column vector, if yours isn't call w = w(:) to ensure that it is
n = 5;
%Pad w so that it's length is divisible by n
padded = [w; nan(n - mod(length(w), n), 1)];
segmented_w = reshape(padded, n, []);
max(segmented_w)