Dynamic window forming in efficient way in MATLAB - matlab

Can someone help me to provide an efficient way or help me to perform the provide code to do make same results in minimal possible steps. I shall be grateful to you.
I have an Original Array:
A = [1 1 1 4.3 4.5 4 4.3 3 1 0 0 2 6.2 6.3 6 6.2 7.4 8 7.2 2 2 3 3 2];
Output Looks like:
A = [1 1 1 4 4 4 4 3 1 0 0 2 6 6 6 6 6 7 7 2 2 3 3 2];
I apply some restrictions and removed some values from array of local maxima’s after that I received some new arrays.
Yposlocfiltered = [6 15 23];
idx = [4 6 3];
Yneglocfiltered = [2 9 20];
idx_neg = [1 1 2];
Where I will find idx(local maxima value) I will check if values behind and ahead are greater make a window.
Example
If I will find 4 and 4.5, 4.3 is greater than 4 include it in backward window
4.3 is greater than 4 include it in forward window.
I need to find range of values behind local maxima and ahead local maxima.
I have tried to write a code that’s works fine but issue is that it’s too long.
Can someone please provide me an idea to perform this action in minimal steps and in faster ways?
I have only provided code for positive local maxima’s as for negative local maxima code Is just replica of this.
Code:only for positive local maximas
clc
clear all
A = [1 0 1 4.3 4.5 5 4.3 3 0 0 0 2 6.2 6.3 7 6.2 7.4 8 7.2 1 2 3 4 2];
Yposlocfiltered = [ 6 15 23];
idx = [4 6 3];
Yneglocfiltered = [2 9 20];
idx_neg = [1 1 2];
for b = 1: numel(idx)
for c = 1:numel(A)
f = Yposlocfiltered(1,b)-c ;
g = Yposlocfiltered(1,b)+c ;
% if (f > 0 && g <= numel(X))
if(f > 0)
if (A(Yposlocfiltered(1,b)-c))> idx(1,b)
else
d= f+1;
z(b)= d;
backward_window = z;
break
end
end
end
end
for r = 1: numel(idx)
for s = 1:numel(A)
u = Yposlocfiltered(1,r)-s ;
v = Yposlocfiltered(1,r)+s ;
% if (f > 0 && g <= numel(X))
if(v <=numel(A))
if (A(Yposlocfiltered(1,r)+s))> idx(1,r)
else
w= v-1;
y(r)= w;
forward_window = y;
break
end
end
end
end
n=4
for i=1:length(backward_window)
range = backward_window(i): forward_window(i);
p = range
if n <= numel(p)
p = range(1:n)
A( p) = idx(i);
else
% if (size(range)<= 3)
A( p) = idx(i);
end
end

From the first look at your code, I believe you can combine your first two for loops into one.
sA = numel(A);
sI = numel(idx);
for i = 1:sI
f = Yposlocfiltered(i) - [1:sA];
g = Yposlocfiltered(i) + [1:sA];
f(f<1) = [];
g(g>sA) = [];
backward_window(i) = f(find(A(f) <= idx(i), 1)) + 1;
forward_window(i) = g(find(A(g) <= idx(i), 1)) - 1;
end
Here, you can use find to locate the element of an array matching the specified condition, i.e. g <= numel(X) or A(f) <= idx(i).
Your last loop which modifies A can also be integrated into the same loop, so you can have:
sA = numel(A);
sI = numel(idx);
n=4;
for i = 1:sI
f = Yposlocfiltered(i) - [1:sA];
g = Yposlocfiltered(i) + [1:sA];
f(f<1) = [];
g(g>sA) = [];
backward_window(i) = f(find(A(f) <= idx(i), 1)) + 1;
forward_window(i) = g(find(A(g) <= idx(i), 1)) - 1;
range = backward_window(i) : forward_window(i);
if n <= numel(range)
A(range(1:n)) = idx(i);
else
A(range) = idx(i);
end
end

Related

Function to accept a matrix as input and goes element by element using for-loops adding one to each of the elements

I have created a function to add one to an element as follows;
function xz = addOne(x)
nrow = size(x,1);
ncol = size(x,1);
for K = 1:nrow
for J = 1:ncol
xz = x(:) + 1;
end
end
Example: given 1 the function results in 2:
addOne(1) [2]
I have tried using a matrix as an argument for the function...
x = [1 2 3; 0 0 0; 4 5 6];
x =
1 2 3
0 0 0
4 5 6
addOneWithFors(x)
ans =
2
1
5
3
1
6
4
1
7
How would I update this function to accept a matrix with multiple rows and columns and output it as such instead of just 1 number or a list of elements. Any help would be greatly appreciated.
In Matlab, you don't need a special function to do this. Matlab natively supports adding a scalar to a matrix. For example:
x = [1 2 3; 0 0 0; 4 5 6];
y = x + 1
will produce:
y =
2 3 4
1 1 1
5 6 7
However, if you specifically want to write this out explicitly using for loops, then your addOne() function only needs minor modifications. For example:
function xz = addOne(x)
nrow = size(x,1);
ncol = size(x,2);
xz = zeros(nrow,ncol);
for K = 1:nrow
for J = 1:ncol
xz(K,J) = x(K,J) + 1;
end
end
Note that ncol = size(x,2); has been defined correctly.

How to generate matrix in MATLAB where values decrease with increasing coordinates

I'm trying to generate an n x n matrix like
5 4 3 2 1
4 4 3 2 1
3 3 3 2 1
2 2 2 2 1
1 1 1 1 1
where n = 5 or n 50. I'm at an impasse and can only generate a portion of the matrix. It is Problem 2.14 from Numerical Methods using MATLAB 3rd Edition by Penny and Lindfield. This is the best I have so far:
n = 5;
m = n;
A = zeros(m,n);
for i = 1:m
for j = 1:n
A(i,j) = m;
end
m = m - 1;
end
Any feedback is appreciated.
That was a nice brain-teaser, here’s my solution:
[x,y] = meshgrid(5:-1:1);
out = min(x,y)
Output:
ans =
5 4 3 2 1
4 4 3 2 1
3 3 3 2 1
2 2 2 2 1
1 1 1 1 1
Here's one loop-based approach:
n = 5;
m = n;
A = zeros(m, n);
for r = 1:m
for c = 1:n
A(r, c) = n+1-max(r, c);
end
end
And here's a vectorized approach (probably not faster, just for fun):
n = 5;
A = repmat(n:-1:1, n, 1);
A = min(A, A.');
That's one of the matrices in Matlab's gallery, except that it needs a 180-degree rotation, which you can achieve with rot90:
n = 5;
A = rot90(gallery('minij', n), 2);

smart way of element accessing in an array to perform certain actions in MATLAB

Sorry for asking question again but it is different from my previously asked question just the arrays are same but query is different.
I have an original array
A = [1 0 1 4.3 4.5 5 4.3 3 0 0 0 2 6.2 6.3 7 6.2 7.4 8 7.2 1 2 3 4 2];
Expected Output from code:
A = [1 1 1 4 4 4 1 1 1 0 0 2 6 6 6 6.2 7.4 8 2 2 2 3 3 2];
I have found Positive Local maxima’s and negative Local maxima’s in an array A and after that I applied some limitations and removed some maxima’s and minima’s and the formed an array with local maximas and minimas in order .
Array Containing Positive and negative local maxima’s in order along with location.
Yloc = [2 6 9 15 20 23];
Ymaximaminimanew = [0 5 0 7 1 4];
Now I separated locations of positive and negative local maximas from Yloc.
Yposlocfiltered = [ 6 15 23];
Yneglocfiltered = [2 9 20];
What I want:
I want to make a loop that checks the values in Ymaximaminimanew if negative local maximas comes first then do certain action that is linked with negative local maxima and if the value belongs to positive local maxima then do certain action that belongs to positive local maxima.
Example
Like in Ymaximaminimanew first is 0 which belongs to negative local maxima
then do the action. Please have a look at attached code it will go to elseif
and perform the task.
2nd value is 5 which is positive local maxima so it will go to if and
perform the task.
The logic I have used is provided in the code. If someone suggest me better logic to make my code smarter then it will be nice.
I have some issue with the code I am not getting the desired output what I am expecting. Just a small error may be in formatting of loop.
I have some issue with loop 4 when t=4 its starts misbehaving also If someone let me know how to do this smartly in simple and minimal steps then it will be really nice.
Thanks a lot in advance for your time, expertise and help.
Code:
A = [1 0 1 4.3 4.5 5 4.3 3 0 0 0 2 6.2 6.3 7 6.2 7.4 8 7.2 1 2 3 4 2];
Yposlocfiltered = [ 6 15 23];
Yneglocfiltered = [2 9 20];
Yloc = [2 6 9 15 20 23];
Ymaximaminimanew = [0 5 0 7 1 4];
sA = numel(A);
n=3;
r = 1;
s = 1;
for t = 1:numel(Yloc)
if (ismember(A(Yloc(1,t)),A(Yposlocfiltered)))
x = A(Yposlocfiltered);
x = x(1,r);
poslocations=x ;
idx = poslocations-1;
sI = numel(idx);
f = Yposlocfiltered(1,r) - [1:sA];
g = Yposlocfiltered(1,r) + [1:sA];
f(f<1) = [];
g(g>sA) = [];
backward_window(t) = f(find(A(f) <= idx, 1)) + 1;
forward_window(t) = g(find(A(g) <= idx, 1)) - 1;
r = r+1;
range = backward_window(t) : forward_window(t);
if n <= numel(range)
A(range(1:n)) = idx;
else
A(range) = idx;
end
elseif (ismember(A(Yloc(1,t)),A(Yneglocfiltered)))
c = A( Yneglocfiltered);
c = c(1,s);
neglocations=c;
idx_neg = neglocations+1;
sU = numel(idx_neg );
h = Yneglocfiltered(1,s) - [1:sA];
p = Yneglocfiltered(1,s) + [1:sA];
h(h<1) = [];
p(p>sA) = [];
backward_window_neg(t) = h(find(A(h) <= idx_neg, 1)) + 1;
forward_window_neg(t) = p(find(A(p) <= idx_neg, 1)) - 1;
range = backward_window_neg(t) : forward_window_neg(t);
s = s + 1;
if n <= numel(range)
A(range(1:n)) = idx_neg;
else
A(range) = idx_neg;
end
end
end

Assigning Values to the neighbors same value in MATLAB

I am having a small issue but I am clueless where I am at fault. Can someone please guide me the right way? Thanks in advance.
What I have done.
My codes finds local maxima’s.
Bring down from local maxima to a certain point.
Assign the neighbors that are greater than the downsized value, the value of downsized point.
Small Example
X = [1 0 1 4.3 4.5 5 4.3 4.2 0 0 0 2 6.2 6.3 7 6.2 7.4 8 7.2 1 2 3 4 2];
Local maxima’s are 5, 7, 8, and 4
Go down to certain point. Like 4, 6, 7, 3.
Assign neighbors that have values greater than 4,6,7,3 same values.
Output will be like
X = [1 0 1 4 4 4 4 4 0 0 0 2 6 6 6 6 6 6 6 1 2 3 3 2];
As this was a simple example so did not have much difference when I applied my code on it.
I have provided another example with my code. Please have a look at that.
t = 50;
X = sin(2*pi*10*(1:t)/t) + 0.5*sin(2*pi*5*(1:50)/t) - linspace(0,3,50);
% plot(X)
A= X;
% A1 = [1 0 1 4.3 4.5 5 4.3 4.2 0 0 6 6 6 6 6 6 6 6 6 1 2 3 4 2];
[pks,locs] = findpeaks(A);
idx = A(locs)-0.3 ; % will bring local maxima to the point where we want
for b = 1: numel(idx) % loop for checking idx
for c = 1:numel(A) % loop for checking neighbourhoods
if (A(locs(1,b)-c)> idx(1,b) && A(locs(1,b)+c)> idx(1,b))
else
d= c-1;
z(b)= d;
break
end
end
end
for i = 1:numel(idx)
for n = 1:z(1,i)
idx_1 = A(locs(i) - n); % will find what is in neighbourhood of local maxima
idx_2 = A(locs(i) + n);
% idx_1 = A(locs - n); % will find what is in neighbourhood of local maxima
% idx_2 = A(locs + n);
if (idx_1>idx(1,i) && (idx_2>idx(1,i))) % Check and assign the same value to neighbourhood of local maxima
A(locs(1,i)) = idx(i);
A(locs(1,i)-n) = idx(i);
A(locs(1,i)+n) = idx(i);
% A(i)) = A(idx(i))
else if (idx_1 < idx(1,i) && (idx_2>idx(1,i)))
A(locs(1,i)) = idx(i);
A(locs(1,i)+n) = idx(i);
else if (idx_1 > idx(1,i) && (idx_2<idx(1,i)))
A(locs(1,i)) = idx(i);
A(locs(1,i)-n) = idx(i);
else
A(locs(1,i)) = idx(i);
A(locs(1,i)-n) = idx_1(i);
A(locs(1,i)+n) = idx_1(i);
end
end
end
end
A(locs(1,i)) = idx(i);
end
figure(1)
hold on
plot(X,'r')
plot(A,'b')
hold off
Expected Output be like Black line in the picture not blue lines that are formed from code

How to create a random path between two known points in matrix in MATLAB

If there is a matrix and two known points, how to create one random path (no need to be the shortest) between these two points with:
a path that can have a level of deviation
a path can be totally random (but not necessary)
the next step can be only from 4 neighbors
ex.
5x5 matrix with two known points: (2,1) and (5,5)
After input: pt1 = [2,1]; pt2 = [5,5];.
How could I get the pattern such as follows with the path recorded in the parameter, such aspath = [2,1;2,2-;3,2;4,2;4,3;4,4;4,5;5,5].
X X X X X
o o X X X
X o X X X
X o o o o
X X X X o
PART A - Aim is to find coordinates of a line/path connecting two points on a 2D domain such that no two neighboring coordinates are diagonal to each other i.e. that is left/right/top/bottom only.
Function codes
function pts_array = points_array(pt1,pt2)
if pt1(1)==pt2(1)
if pt2(2)>pt1(2)
pts_array = [repmat(pt1(1),(pt2(2)-pt1(2)+1),1) (pt1(2):pt2(2))'];
elseif pt2(2)<pt1(2)
pts_array = flipud([repmat(pt1(1),(pt1(2)-pt2(2)+1),1) (pt2(2):pt1(2))']);
else
pts_array = pt1;
end
elseif pt1(2)==pt2(2)
if pt2(1)>pt1(1)
pts_array = [(pt1(1):pt2(1))' repmat(pt1(2),(pt2(1)-pt1(1)+1),1)];
elseif pt2(1)<pt1(1)
pts_array = flipud([(pt2(1):pt1(1))' repmat(pt1(2),(pt1(1)-pt2(1)+1),1)]);
else
pts_array = pt1;
end
else
gslope1_org = (pt2(2)-pt1(2))/(pt2(1)-pt1(1));
if gslope1_org <1
pt1 = fliplr(pt1);
pt2 = fliplr(pt2);
end
gslope1 = (pt2(2)-pt1(2))/(pt2(1)-pt1(1));
off1 = 1;
pts_array = [pt1];
gpt1 = pt1;
while 1
slope1 = (pt2(2)-gpt1(2))/(pt2(1)-gpt1(1));
if (slope1<gslope1)
gpt1 = [gpt1(1)+off1 gpt1(2)];
pts_array = [pts_array; gpt1];
else
new_y = floor(gpt1(2)+slope1);
range_y = (gpt1(2)+1 : floor(gpt1(2)+slope1))';
gpt1 = [gpt1(1) new_y];
pts_array = [pts_array ; [repmat(gpt1(1),[numel(range_y) 1]) range_y]];
end
if isequal(gpt1,pt2)
break;
end
end
if gslope1_org <1
pts_array = fliplr(pts_array);
end
end
function pts_array = points_array_wrap(pt1,pt2) %%// Please remember that this needs points_array.m
x1 = pt1(1);
y1 = pt1(2);
x2 = pt2(1);
y2 = pt2(2);
quad4 = y2<y1 & x2>x1; %% when pt2 is a lower height than pt1 on -slope
quad3 = y2<y1 & x2<x1; %% when pt2 is a lower height than pt1 on +slope
quad2 = y2>y1 & x2<x1; %% when pt2 is a higher height than pt1 on -slope
if quad4
y2 = y2+ 2*(y1 - y2);
end
if quad2
y2 = y2 - 2*(y2 - y1);
t1 = x1;t2 = y1;
x1 = x2;y1 = y2;
x2 = t1;y2 = t2;
end
if quad3
t1 = x1;t2 = y1;
x1 = x2;y1 = y2;
x2 = t1;y2 = t2;
end
pts_array = points_array([x1 y1],[x2 y2]);
if quad4
offset_mat = 2.*(pts_array(:,2)-pt1(2));
pts_array(:,2) = pts_array(:,2) - offset_mat;
end
if quad3
pts_array = flipud(pts_array);
end
if quad2
offset_mat = 2.*(pt1(2)-pts_array(:,2));
pts_array(:,2) = pts_array(:,2) + offset_mat;
pts_array = flipud(pts_array);
end
return;
Script
pt1 = [2 1];
pt2 = [5 5];
pts_array = points_array_wrap(pt1,pt2);
plot(pts_array(:,1),pts_array(:,2),'o'), grid on, axis equal
for k = 1:size(pts_array,1)
text(pts_array(k,1),pts_array(k,2),strcat('[',num2str(pts_array(k,1)),',',num2str(pts_array(k,2)),']'),'FontSize',16)
end
Output
pts_array =
2 1
2 2
3 2
3 3
4 3
4 4
4 5
5 5
Plot
PART B - Aim is to find coordinates of a line/path connecting two points on a 2D domain through given spaces.
In this special case, we are assuming that there are some spaces and only through which the path is to be connected. This is not asked by OP, but I thought it could interesting to share. So, for this, the spaces would be the o's as shown in OP's question.
Code
function your_path = path_calc(mat1,starting_pt,final_pt)
[x1,y1] = find(mat1);
pt1 = [x1 y1];
d1 = pdist2(pt1,final_pt,'euclidean');
[~,ind1] = sort(d1,'descend');
path1 = pt1(ind1,:);
your_path = path1(find(ismember(path1,starting_pt,'rows')):end,:);
return;
Run - 1
%%// Data
mat1 = zeros(5,5);
mat1(2,1:2) = 1;
mat1(3,2) = 1;
mat1(4,2:5) = 1;
mat1(5,5) = 1;
starting_pt = [2 1];
final_pt = [5 5];
%%// Path traces
path = path_calc(mat1,starting_pt,final_pt);
Gives -
mat1 =
0 0 0 0 0
1 1 0 0 0
0 1 0 0 0
0 1 1 1 1
0 0 0 0 1
path =
2 1
2 2
3 2
4 2
4 3
4 4
4 5
5 5
Run - 2
%%// Data
mat1 = zeros(5,5);
mat1(2,1:2) = 1;
mat1(3,2) = 1;
mat1(4,2:5) = 1;
mat1(5,5) = 1;
mat1 = fliplr(mat1');
%%// Notice it starts not from the farthest point this time
starting_pt = [2 3];
final_pt = [5 1];
%%// Path traces
path = path_calc(mat1,starting_pt,final_pt);
Gives
mat1 =
0 0 0 1 0
0 1 1 1 0
0 1 0 0 0
0 1 0 0 0
1 1 0 0 0
path =
2 3
2 2
3 2
4 2
5 2
5 1
To find a purely random path from the start to the goal, this function selects a random direction, checks that there is a valid neighbor in that direction and if there is, moves to that new neighbor and adds it to the path.
Directions can be invalid if, for instance, we're in the leftmost column and try to move left. We could check beforehand and only select randomized directions that lead to valid neighbors, but that would complicate the code and the chances of selecting a valid neighbor are at worst 50/50.
function path = random_path(start, goal, board_size)
m = board_size(1);
n = board_size(2);
isInBounds = #(x) x(1) >= 1 && x(1) <= m && x(2) >= 1 && x(2) <= n;
neighbor_offset = [ 0, -1; % Neighbor indices:
-1, 0; % 2
0, 1; % 1 x 3
1, 0]; % 4
% Edit: get the actual size of our neighbor list
[possible_moves, ~] = size(neighbor_offset);
current_position = start;
path = current_position;
while sum(current_position ~= goal) > 0
valid = false;
while ~valid
% Edit: "magic numbers" are bad; fixed below
% move = randi(4);
move = randi(possible_moves);
candidate = current_position + neighbor_offset(move, :);
valid = isInBounds(candidate);
end
current_position = candidate;
path = [path; current_position];
end
end
The while condition:
sum(current_position ~= goal) > 0
continues while at least one of the coordinates of sum and goal are different. I'm sure this could be written more concisely, so if there are any suggestions as to how to improve this I'd be grateful.
Likewise, the isInBounds anonymous function also seems a bit clunky, so any suggestions there would be appreciated as well.
At any rate, here's a sample of the output. Since the paths are completely random, some of them can get quite long:
random_path([2,1], [5,5], [5,5])
ans =
2 1
3 1
2 1
3 1
3 2
4 2
4 1
5 1
4 1
4 2
3 2
3 1
2 1
1 1
2 1
3 1
3 2
4 2
4 3
4 4
4 3
4 2
4 3
5 3
4 3
3 3
4 3
4 2
4 1
4 2
4 1
4 2
4 3
4 2
5 2
5 3
5 2
4 2
3 2
3 3
3 4
3 5
3 4
2 4
3 4
4 4
5 4
5 3
4 3
3 3
3 2
4 2
4 3
4 4
5 4
5 5