Related
How do I program a function that takes two matrices A and B as input and outputs the product matrix A*B? Using MATLAB, with loops and conditionals.
My attempt:
function prodAB=MultiplicoMatrices(A,B)
prod=0;
prodAB=[];
for i=1:length(A)
for j=1:length(B)
prod=prod+A(i,j)*B(j,i);
end
prodAB(i,j)=prod;
prod=0;
end
A =
1 2
3 4
B=[5 6 ; 7 8]
B =
5 6
7 8
>> prodAB=MultiplicoMatrices([1 2; 3 4],[5 6; 7 8])
prodAB =
0 19
0 50
You mean the triple-loop algorithm? You could write the function as follows.
function prodAB = MultiplicoMatrices(A,B)
prodAB = zeros(size(A,1),size(B,2));
for i = 1:size(A,1)
for j = 1:size(B,2)
prod = 0;
for k = 1:size(A,2)
prod = prod + A(i,k) * B(k,j);
end
prodAB(i,j) = prod;
end
end
end
Now test it,
A = [1 2; 3 4];
B = [5 6; 7 8];
MultiplicoMatrices(A,B)
ans =
19 22
43 50
A * B
ans =
19 22
43 50
so, it works.
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.
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
I want to combine columns of matrices, for example,
A=[1,2,3;4,5,6]';B=[1,3,5;2,9,0]';
and I want
C1=[1,2,3;1,3,5]'
C2=[1,2,3;2,9,0]'
C3=[4,5,6;1,3,5]'
C4=[4,5,6;2,9,0]'
How do I do that in matlab? Is there a function that does this?
Thanks!
This should do the trick:
A=[1,2,3;4,5,6]';
B=[1,3,5;2,9,0]';
Cs = [];
index = 0;
for i = 1:length(A(1,:))
for j = 1:length(B(1,:))
index += 1;
Cs(:,:,index) = [A(:,i), B(:,j)];
end
end
Cs
Is this what you want?
[ii, jj] = ndgrid(1:size(A,2));
C = permute(cat(3, A(:,jj), B(:,ii)), [1 3 2]);
The result is a 3D array such that (C(:,:,1) is your C1, etc:
C(:,:,1) =
1 1
2 3
3 5
C(:,:,2) =
1 2
2 9
3 0
C(:,:,3) =
4 1
5 3
6 5
C(:,:,4) =
4 2
5 9
6 0
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