Find X,Y points in polyshape - Matlab - matlab

In a poylshape, how can I find all the Y points when X is defined as 0.5 and how to find all the X point when Y is defined as 0.75? (the searched numbers can be changed)
Code:
clc;
clear all;
close all;
P = [0.5 0.5; 1 0.75; 0.5 0.75; 0.8 0.8; 0.25 1; 0 1];
pgon = polyshape(P)
plot(pgon)

Logically Indexing a Given Column
One way to get matching pairs is to use logical indexing on a given column and use that to index the complementary column. In the case that the X is known we can use that to evaluate which indices in column one are equal to a certain value and then use this indices to obtain the corresponding Y values in the second column. The vice-versa case is similar when Y is known/given.
clc;
P = [0.5 0.5; 1 0.75; 0.5 0.75; 0.8 0.8; 0.25 1; 0 1];
pgon = polyshape(P);
plot(pgon);
%Inputting X-coordinate%
X = 0.5;
Y_Points = P(P(:,1) == X,2);
X_Points = repmat(X,[length(Y_Points) 1]);
disp("X: " + num2str(X));
arrayfun(#(x,y) fprintf("(x,y) -> (%.2f,%.2f)\n",x,y), X_Points,Y_Points);
fprintf("\n")
%Inputting Y-coordinate%
Y = 0.75;
X_Points = P(P(:,2) == Y,1);
Y_Points = repmat(Y,[length(X_Points) 1]);
disp("Y: " + num2str(Y));
arrayfun(#(x,y) fprintf("(x,y) -> (%.2f,%.2f)\n",x,y), X_Points,Y_Points);
Output Results:
X: 0.5 (x,y) -> (0.50,0.50) (x,y) -> (0.50,0.75)
Y: 0.75 (x,y) -> (1.00,0.75) (x,y) -> (0.50,0.75)

Related

Using 'fminunc', I receive Optimization completed because the size of the gradient is less than the value of the optimality tolerance

I use fminunc to find the value of B (2x4 matrix) that minimzes the difference between the corresponding elements in two vectors as indicated in the attached code. In other words, I want to find the B that makes the elements of beta_d (1x4 vector) which is a function of B matrix, equal to the corresponding ones of a "given" beta_u (1x4 vector), i.e. beta_d(1,1) = beta_u(1,1) && beta_d(1,2) = beta_u(1,2) && beta_d(1,3) = beta_u(1,3) && beta_d(1,4) = beta_u(1,4).
However, I usually receive the following message without getting any result and the program seems to go on an infinite loop!
Local minimum found.
Optimization completed because the size of the gradient is less than
the value of the optimality tolerance.
<stopping criteria details>
The code is as follows:
% System paramters:
N = 2;
K = 4;
C_l = 4;
H = [-0.3208 -0.9784; -1.5994 -1.4689; -1.5197 -0.4568; -0.0993 -0.7667]; % 4*2 matrix
A = [-1 1; 0 1]; % 2x2 matrix
C = [-0.20 0.4 0.6 -0.2; -0.2 0.4 0.6 -0.2; 0.4 0.2 -0.2 0.4; 0.4 0.2 -0.2 0.4]; % 4x4 matrix
P = [250000 0 0 0; 0 250000 0 0; 0 0 250000 0; 0 0 0 250000]; % 4x4 matrix
beta_u = [50.2207 50.2207 20.3433 20.3433]; % 1x4 vector
beta_d = zeros(1,4); % intial value
B = zeros(2,4); % intial value
% store inputs to a struct for shorter syntax
s = struct();
[s.H,s.A,s.C,s.P,s.C_l,s.N,s.K] = deal(H,A,C,P,C_l,N,K);
%fminunc optimization
while (sum(abs(beta_u-beta_d))>=0.1)
initial_guess = randn(2,4);
OLS = #(B_d,input_vars)sum((beta_u-myfun(B_d,input_vars)).^2); % ordinary least squares cost function
opts = optimoptions(#fminunc,'MaxIterations',10000,'MaxFunctionEvaluations',50000,'CheckGradients',true);
B = fminunc(OLS, initial_guess, opts,s);
input_vars = s;
[beta_d, D_d] = myfun(B,input_vars);
end
% calculate beta_d from B and the other inputs
function [beta_d, D_d] = myfun(B,input_vars)
% load parameters
s = input_vars;[H,A,C,P,C_l,N,K]=deal(s.H,s.A,s.C,s.P,s.C_l,s.N,s.K);
for j = 1:1:N
d(j) = (B(j,:)*P*B(j,:)')/((2^(2*C_l))-(norm(A(:,j))^2));
end
D_d = diag(d);
for i = 1:1:K
V_d(i) = C(i,:)*P*B'*H(i,:)'*inv(1+H(i,:)*(A'*D_d*A+B*P*B')*H(i,:)');
sigma_d(i) = norm((V_d(i)*H(i,:)*B-C(i,:))*(P^(1/2)))^2+(V_d(i)^2)*(1+H(i,:)*A'*D_d*A*H(i,:)');
beta_d(i) = ((P(i,i))/sigma_d(:,i));
end
end

How can I hot one encode in Matlab? [duplicate]

This question already has answers here:
Create a zero-filled 2D array with ones at positions indexed by a vector
(4 answers)
Closed 5 years ago.
Often you are given a vector of integer values representing your labels (aka classes), for example
[2; 1; 3; 3; 2]
and you would like to hot one encode this vector, such that each value is represented by a 1 in the column indicated by the value in each row of the labels vector, for example
[0 1 0;
1 0 0;
0 0 1;
0 0 1;
0 1 0]
For speed and memory savings, you can use bsxfun combined with eq to accomplish the same thing. While your eye solution may work, your memory usage grows quadratically with the number of unique values in X.
Y = bsxfun(#eq, X(:), 1:max(X));
Or as an anonymous function if you prefer:
hotone = #(X)bsxfun(#eq, X(:), 1:max(X));
Or if you're on Octave (or MATLAB version R2016b and later) , you can take advantage of automatic broadcasting and simply do the following as suggested by #Tasos.
Y = X == 1:max(X);
Benchmark
Here is a quick benchmark showing the performance of the various answers with varying number of elements on X and varying number of unique values in X.
function benchit()
nUnique = round(linspace(10, 1000, 10));
nElements = round(linspace(10, 1000, 12));
times1 = zeros(numel(nUnique), numel(nElements));
times2 = zeros(numel(nUnique), numel(nElements));
times3 = zeros(numel(nUnique), numel(nElements));
times4 = zeros(numel(nUnique), numel(nElements));
times5 = zeros(numel(nUnique), numel(nElements));
for m = 1:numel(nUnique)
for n = 1:numel(nElements)
X = randi(nUnique(m), nElements(n), 1);
times1(m,n) = timeit(#()bsxfunApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times2(m,n) = timeit(#()eyeApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times3(m,n) = timeit(#()sub2indApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times4(m,n) = timeit(#()sparseApproach(X));
X = randi(nUnique(m), nElements(n), 1);
times5(m,n) = timeit(#()sparseFullApproach(X));
end
end
colors = get(0, 'defaultaxescolororder');
figure;
surf(nElements, nUnique, times1 * 1000, 'FaceColor', colors(1,:), 'FaceAlpha', 0.5);
hold on
surf(nElements, nUnique, times2 * 1000, 'FaceColor', colors(2,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times3 * 1000, 'FaceColor', colors(3,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times4 * 1000, 'FaceColor', colors(4,:), 'FaceAlpha', 0.5);
surf(nElements, nUnique, times5 * 1000, 'FaceColor', colors(5,:), 'FaceAlpha', 0.5);
view([46.1000 34.8000])
grid on
xlabel('Elements')
ylabel('Unique Values')
zlabel('Execution Time (ms)')
legend({'bsxfun', 'eye', 'sub2ind', 'sparse', 'full(sparse)'}, 'Location', 'Northwest')
end
function Y = bsxfunApproach(X)
Y = bsxfun(#eq, X(:), 1:max(X));
end
function Y = eyeApproach(X)
tmp = eye(max(X));
Y = tmp(X, :);
end
function Y = sub2indApproach(X)
LinearIndices = sub2ind([length(X),max(X)], [1:length(X)]', X);
Y = zeros(length(X), max(X));
Y(LinearIndices) = 1;
end
function Y = sparseApproach(X)
Y = sparse(1:numel(X), X,1);
end
function Y = sparseFullApproach(X)
Y = full(sparse(1:numel(X), X,1));
end
Results
If you need a non-sparse output bsxfun performs the best, but if you can use a sparse matrix (without conversion to a full matrix), then that is the fastest and most memory efficient option.
You can use the identity matrix and index into it using the input/labels vector, for example if the labels vector X is some random integer vector
X = randi(3,5,1)
ans =
2
1
2
3
3
then, the following will hot one encode X
eye(max(X))(X,:)
which can be conveniently defined as a function using
hotone = #(v) eye(max(v))(v,:)
EDIT:
Although the solution above works in Octave, you have you modify it for Matlab as follows
I = eye(max(X));
I(X,:)
I think this is fast specially when matrix dimension grows:
Y = sparse(1:numel(X), X,1);
or
Y = full(sparse(1:numel(X), X,1));
Just posting the sub2ind solution too to satisfy your curiosity :)
But I like your solution better :p
>> X = [2,1,2,3,3]'
>> LinearIndices = sub2ind([length(X),3], [1:length(X)]', X);
>> tmp = zeros(length(X), 3);
>> tmp(LinearIndices) = 1
tmp =
0 1 0
1 0 0
0 1 0
0 0 1
0 0 1
Just in case someone is looking for the 2D case (as I was):
X = [2 1; ...
3 3; ...
2 4]
Y = zeros(3,2,4)
for i = 1:4
Y(:,:,i) = ind2sub(X,X==i)
end
gives a one-hot encoded matrix along the 3rd dimension.

Create a relation matrix from a sequence (Matlab)

I have a sequence S :
S= 'ABCD' % which means A<B<C<D
I want to convert S into a matrix M[i,j] which have to satisfy those conditions :
M[i,j] , M[j,i] are random
M[i,i] =0.5
M[i,j] + M[j,i] = 1
M[i,j] < M[j,i] % For example: if A<B then M[A,B] < M[B,A]
For example: if we have S = 'ABCD', the M matrix will be expected as follows:
A B C D
A o.5 0.25 0.2 0.1
B 0.75 0.5 0.35 0.15
C 0.8 0.65 0.5 0.4
D 0.9 0.85 0.6 0.5
How to create that kind of above matrix from a given sequence ?
From your question it appears you want
to fill the lower part of the matrix with random entries uniformly distributed on the interval (0,0.5) (so that condition 4 in your question be satisfied);
the upper part is then computed according to condition 3; and
the diagonal is determined by condition 2.
You can do that as follows:
n = 4; %// size
M = NaN(n); %// preallocate
M(1:n+1:end) = 0.5; %// fill diagonal
ind_lower = tril(true(n), -1); %// logical index for lower part
M(ind_lower) = 0.5*rand(n*(n-1)/2, 1); %// fill lower part
M_aux = NaN(n); %// auxiliary variable to fill upper part
M_aux(ind_lower) = 1-M(ind_lower).';
M_aux = M_aux.';
M(ind_lower.') = M_aux(ind_lower.'); %// fill upper part
Example result:
M =
0.5000 0.5214 0.7573 0.5999
0.4786 0.5000 0.9291 0.7891
0.2427 0.0709 0.5000 0.5421
0.4001 0.2109 0.4579 0.5000
Here's another similar approach:
n = 4;
M = tril(rand(n)*0.5, -1);
P = triu(1-M.', 1);
M = M + P + eye(n)*0.5;
Result:
M =
0.500000 0.987433 0.711005 0.944642
0.012567 0.500000 0.782633 0.902365
0.288995 0.217367 0.500000 0.783708
0.055358 0.097635 0.216292 0.500000

Matlab, Error using surf, X, Y, Z, and C cannot be complex

i run below code, but get X, Y, Z, and C cannot be complex error, any idea what is wrong?
k=1;
u = linspace(0,2*pi,72);
v = [-3:.2:-1,1:.2:3];
[U,V] = meshgrid(u,v);
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
X = r.*cos(U);
Y = r.*sin(U);
Z = V;
This is the image I want to get:
http://adasu.info/plates.png
The full code is:
function simple_math_functions_animation1
clc, close all, clear all
hf1=figure(1);hold on,grid on,axis equal, view([1 -1 1])
set(hf1,'Color','w');set(hf1,'Position',[300, 600, 500, 400]);
xlabel('x');ylabel('y'),zlabel('z');
k=1;
u = linspace(0,2*pi,72);
v = [-3:.2:-1,1:.2:3];
[U,V] = meshgrid(u,v);
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
X = r.*cos(U);
Y = r.*sin(U);
Z = V;
surf(X,Y,Z,'EdgeColor',[0.5 1. 0.2],'FaceColor',[1 0.2 0.8],'FaceAlpha',0.6);
XYZ=[reshape(X,1,prod(size(X)));
reshape(Y,1,prod(size(Y)));
reshape(Z,1,prod(size(Z)));
ones(1,prod(size(Z)))];
phi=[0 : pi/20 : 50*pi];
h=[]; axis([-20 20 -20 20 -20 20]);
for beta=phi % animation loop *****************
T=[cos(beta) -sin(beta) 0 0; % rotation matrix
sin(beta) cos(beta) 0 0;
0 0 1 0;
0 0 0 1];
XYZ1=T*XYZ; % coordinates changing
X1=reshape(XYZ1(1,:),size(X));Y1=reshape(XYZ1(2,:),size(Y));Z1=reshape(XYZ1(3,:),size(Z));
pause(0.1);if ~isempty(h),delete(h);end
h=surf(X1,Y1,Z1,'EdgeColor',[0.5 1. 0.2],'FaceColor',[0.2 0.2 0.8],'FaceAlpha',0.6);
end % ******************************************
end
You are getting that complex error because r is complex-valued. r is used in both X and Y and so when it's time to use surf on these inputs, you finally get that error. That makes sense because your range of V has negative values, and when you set k=1 for this expression:
r=sqrt((4*V.^-k)./(cos(U).^2+k*sin(U).^2));
You are effectively trying to take the square root of values in V and some of them are negative, and hence r is complex valued. If you look at your actual image you uploaded, you are missing a 2 in the power of V. Therefore:
r=sqrt((4*V.^2-k)./(cos(U).^2+k*sin(U).^2));
When I do this, then try running your code, I get this:

Finding sub-matrix with minimum elementwise sum

I have a symmetric m-by-m matrix A. Each element has a value between 0 and 1. I now want to choose n rows / columns of A which form an n-by-n sub-matrix B.
The criteria for choosing these elements, is that the sum of all elements of B must be the minimum out of all possible n-by-n sub-matrices of A.
For example, suppose that A is a 4-by-4 matrix:
A = [0 0.5 1 0; 0.5 0 0.5 0; 1 0.5 1 1; 0 0 1 0.5]
And n is set to 3. Then, the best B is the one taking the first, second and fourth rows / columns of A:
B = [0 0.5 0; 0.5 0 0; 0 0 0.5]
Where the sum of these elements is 0 + 0.5 + 0 + 0.5 + 0 + 0 + 0 + 0 + 0.5 = 1.5, which is smaller than another other possible 3-by-3 sub-matrices (e.g. using the first, third and fourth rows / columns).
How can I do this?
This is partly a mathematics question, and partly a Matlab one. Any help with either would be great!
Do the following:
m = size(A,1);
n=3;
sub = nchoosek(1:m,n); % (numCombinations x n)
subR = permute(sub,[2,3,1]); % (n x 1 x numCombinations), row indices
subC = permute(sub,[3,2,1]); % (1 x n x numCombinations), column indices
lin = bsxfun(#plus,subR,m*(subC-1)); % (n x n x numCombinations), linear indices
allB = A(lin); % (n x n x numCombinations), all possible Bs
sumB = sum(sum(allB,1),2); % (1 x 1 x numCombinations), sum of Bs
sumB = squeeze(sumB); % (numCombinations x 1), sum of Bs
[minB,minBInd] = min(sumB);
fprintf('Indices for minimum B: %s\n',mat2str(sub(minBInd,:)))
fprintf('Minimum B: %s (Sum: %g)\n',mat2str(allB(:,:,minBInd)),minB)
This looks only for submatrices where the row indices are the same as the column indices, and not necessarily consecutive. That is how I understood the question.
This is a bit brute force, but should work
A = [0 0.5 1 0; 0.5 0 0.5 0; 1 0.5 1 1; 0 0 1 0.5];
sizeA = size(A,1);
size_sub=3;
idx_combs = nchoosek(1:sizeA, size_sub);
for ii=1:size(idx_combs,1)
sub_temp = A(idx_combs(ii,:),:);
sub = sub_temp(:,idx_combs(ii,:));
sum_temp = sum(sub);
sums(ii) = sum(sum_temp);
end
[min_set, idx] = min(sums);
sub_temp = A(idx_combs(idx,:),:);
sub = sub_temp(:,idx_combs(idx,:))
Try to convolve the matrix A with a smaller matrix M. Eg if you is interested in finding the 3x3 submatrix then let M be ones(3). This code shows how it works.
A = toeplitz(10:-1:1) % Create a to eplitz matrix (example matrix)
m = 3; % Submatrix size
mC = ceil(m/2); % Distance to center of submatrix
M = ones(m);
Aconv = conv2(A,M); % Do the convolution.
[~,minColIdx] = min(min(Aconv(1+mC:end-mC,1+mC:end-mC))); % Find column center with smallest sum
[~,minRowIdx] = min(min(Aconv(1+mC:end-mC,minColIdx+mC),[],2)); % Find row center with smlest sum
minRowIdx = minRowIdx+mC-1 % Convoluted matrix is larger than A
minColIdx = minColIdx+mC-1 % Convoluted matrix is larger than A
range = -mC+1:mC-1
B = A(minRowIdx+range, minColIdx+range)
The idea is to imitate a fir filter y(n) = 1*x(n-1)+1*x(n)+1*x(n+1). For now it only finds the first smallest matrix though. Notice the +1 adjustment because first matrix element is 1. Then notice the the restoration right below.