I have a matrix A of size 50 X 6 and I have a vector x of size 50 X 1. Assume that all columns of A are orthogonal to each other. I have 2 questions:
What is the best way to check whether x is orthogonal to all columns of A or not ? Only solution I can think of is to iterate through every column of A and calculate dot product.
Suppose that from dot products I find that x is not orthogonal to 3rd and 5th column of A then how can I orthogonalize x with respect to all columns of A ?
Thank you for your attention.
The best way to check whether x is orthogonal to every column of A is, like you say, check every column. Luckily, matrix multiplication is the fastest, most heavily optimized operation in all of numerical computing, so A * x is probably going to be fast enough!
About #2, this is the basic idea in Gram-Schmidt orthonormalization. You just have to subtract the piece of x that's represented by the columns of A. In code (sorry I only use Numpy/Python but the same ideas apply to Matlab!):
import numpy as np
# just for demo purposes: build A and x
from scipy.linalg import qr # easy way to generate orthonormal columns
A = qr(np.random.randn(50, 6))[0][:, :6]
x = np.random.randn(50, 1)
# now, #1
is_x_orthogonal = np.allclose(A.T # x, 0) # False :(
# and now, #2
newx = A # (A.T # x) - x
is_newx_orthogonal = np.allclose(A.T # newx, 0) # True :D
You need to compute XT.A which is matrix multiplication of x transpose and A. It will result a row vector of size 6x1. Iff all the element of result vectors are zero then x is orthogonal to all the columns of A.
For part two you need use Graam schmidt technique, only thing special in your case is few term of orthogonality calculation will zero, becoz they are orthogonal,
Related
Could anyone shed some light on how this for loop can be replaced by a single command in MATLAB?
for i = 1 : size(w,3)
x=w(:,:,i);
w1(i,:)=x(B(i),:);
end
clear x
Here, w is a 3D (x by y by z) matrix and B (1 by z) is a vector containing rows pertaining to each layer in w. This for loop takes about 150 seconds to execute when w is 500000 layers deep. I tried using,
Q = w(B,:,:);
Q = reshape(Q(1,:),[500000,2])';
This creates a matrix Q of size 500000 X 2 X 500000 and MATLAB threw me an error saying memory out of bound. Any help would be appreciated!
You are creating intermediate variables (such as x) and using a for loop. The core idea of the following approach is to first pre-populate the indices used and then use linear indexing to access all the elements at once. Then, we can reshape to get the desired result.
ind = [B(1)*ones(size(w,2),1) (1:size(w,2)).' 1*ones(size(w,2),1)];
ind = [ind; [B(2)*ones(size(w,2),1) (1:size(w,2)).' 2*ones(size(w,2),1)]];
ind = [ind; [B(3)*ones(size(w,2),1) (1:size(w,2)).' 3*ones(size(w,2),1)]];
lin_ind = sub2ind(size(w), ind(:,1), ind(:,2), ind(:,3));
w1 = reshape(w(lin_ind),size(w,2),size(w,3)).'
On my system, this matches with w1 computed with the loop given in your question. Note that you may need to use a for loop to pre-populate the indices. I wrote three expressions since I was experimenting with small matrices. Actually, the first three lines can be written in such a way that you don't need loops at all and it still works with any size. I will leave that up to you.
I have a 3 by 3 by 2 by 3 array X containing 1s or 0s. Picture this as a row of three 3 by 3 matrices along a row and another such 'layer' behind them (from the '2').
I want to find the positions in X of the 0s in the first layer and second layer separately. I'm not really sure how to do this with find, but heuristically something like:
A = find(X == 0 & 3rd index of X is 1)
B = find(X == 0 & 3rd index of X is 2)
EDIT
I just realised my attempt to simplify my actual question made it misleading. The array X actually has -1's, 1's and -2's and I want to find the -2's. They're not meant to be logical operators. Also I would prefer any operation proposed to be as fast as possible as this will be part of a recursive backtracking algorithm.
solution using logical indexing
I recommend to use logical indexing instead of find.
This gives you all indices where X is 1
value_you_want=-2
C=X==value_you_want;
Now you want only parts of these indices in A and B, first initialize A and B with false of the same size as C:
A=false(size(C));
B=A;
And finally copy the slice you want to each of these matrices:
A(:,:,1,:)=C(:,:,1,:);
B(:,:,2,:)=C(:,:,2,:);
If you really want your numeric indices, use find(A) and find(B)
Alternative solution using linear indices and find
%get all indices
C=find(X==value_you_want)
%convert linear indices to subscript indices, only use third dimension
[~,~,S,~]=ind2sub(size(X),find(X==0));
%Use S to split C
A=C(S==1);
B=C(S==2);
Generally use find(condition) to return linear indices in the array satisfying condition.
A = find(A(:,:,1,:)<1)
B = find(A(:,:,2,:)<1)
Introduction to problem:
I'm modelling a system where i have a matrix X=([0,0,0];[0,1,0],...) where each row represent a point in 3D-space. I then choose a random row, r, and take all following rows and rotate around the point represented by r, and make a new matrix from these rows, X_rot. I now want to check whether any of the rows from X_rot is equal two any of the rows of X (i.e. two vertices on top of each other), and if that is the case refuse the rotation and try again.
Actual question:
Until now i have used the following code:
X_sim=[X;X_rot];
if numel(unique(X_sim,'rows'))==numel(X_sim);
X(r+1:N+1,:,:)=X_rot;
end
Which works, but it takes up over 50% of my running time and i were considering if anybody in here knew a more efficient way to do it, since i don't need all the information that i get from unique.
P.S. if it matters then i typically have between 100 and 1000 rows in X.
Best regards,
Morten
Additional:
My x-matrix contains N+1 rows and i have 12 different rotational operations that i can apply to the sub-matrix x_rot:
step=ceil(rand()*N);
r=ceil(rand()*12);
x_rot=x(step+1:N+1,:);
x_rot=bsxfun(#minus,x_rot,x(step,:));
x_rot=x_rot*Rot(:,:,:,r);
x_rot=bsxfun(#plus,x_rot,x(step,:));
Two possible approaches (I don't know if they are faster than using unique):
Use pdist2:
d = pdist2(X, X_rot, 'hamming'); %// 0 if rows are equal, 1 if different.
%// Any distance function will do, so try those available and choose fastest
result = any(d(:)==0);
Use bsxfun:
d = squeeze(any(bsxfun(#ne, X, permute(X_rot, [3 2 1])), 2));
result = any(d(:)==0);
result is 1 if there is a row of X equal to some row of X_rot, and 0 otherwise.
How about ismember(X_rot, X, 'rows')?
I have a problem with find. I don't know what is the problem.
I want to find indices in a matrix by respect to another matrix that have same X , Y and different Z.
My matrix are selectedl and selectedf with similar rows and different rows so.
exP=find(selectedl(:,[1,2])==selectedf(:,[1,2]) & selectedl(:,3)~=selectedf(:,3));
what is the issue in the line?
A more readable version would be:
A = selectedl == selectedf;
exP = find(A(:,1) & A(:,2) & ~A(:,3));
If I understand correctly (first column is x, second is y, third is z, each row represents a different point), you just need to add row-wise all in the first part:
exP=find(all(selectedl(:,[1,2])==selectedf(:,[1,2]),2) & selectedl(:,3)~=selectedf(:,3));
Or, perhaps more readable:
exP=find(selectedl(:,1)==selectedf(:,1) & selectedl(:,2)==selectedf(:,2) & selectedl(:,3)~=selectedf(:,3));
This assumes both matrices have the same size and order matters. If not, see #Dan's answer.
You probably should be using ismember instead of find:
[incl, indices] = ismember(selectedl(:,1:2), selectedf(:,1:2), 'rows'); %// Or possibly ismember(selectedf(:,1:2), selectedl(:,1:2), 'rows') depending on what you're after
excl = ismember(selectedl, selectedf, 'rows');
indices(incl & ~excl)
This way your rows don't have to correspond 1 to 1 across the two matrices and teh matrices don't even need to be of the same length.
Lets say I have two vectors A and B with different lengths Length(A) is not equal to Length(B) and the Values in Vector A, are not the same as in Vector B. I want to compare each value of B with Values of A (Compare means if Value B(i) is almost the same value of A(1:end) for example B(i)-Tolerance<A(i)<B(i)+Tolerance.
How Can I do this without using for loop since the data is huge?
I know ismember(F), intersect,repmat,find but non of those function can really help me
You may try a solution along these lines:
tol = 0.1;
N = 1000000;
a = randn(1, N)*1000; % create a randomly
b = a + tol*rand(1, N); % b is "tol" away from a
a_bin = floor(a/tol);
b_bin = floor(b/tol);
result = ismember(b_bin, a_bin) | ...
ismember(b_bin, a_bin-1) | ...
ismember(b_bin, a_bin+1);
find(result==0) % should be empty matrix.
The idea is to discretize the a and b variables to bins of size tol. Then, you ask whether b is found in the same bin as any element from a, or in the bin to the left of it, or in the bin to the right of it.
Advantages: I believe ismember is clever inside, first sorting the elements of a and then performing sublinear (log(N)) search per element b. This is unlike approaches which explicitly construct differences of each element in b with elements from a, meaning the complexity is linear in the number of elements in a.
Comparison: for N=100000 this runs 0.04s on my machine, compared to 20s using linear search (timed using Alan's nice and concise tf = arrayfun(#(bi) any(abs(a - bi) < tol), b); solution).
Disadvantages: this leads to that the actual tolerance is anything between tol and 1.5*tol. Depends on your task whether you can live with that (if the only concern is floating point comparison, you can).
Note: whether this is a viable approach depends on the ranges of a and b, and value of tol. If a and b can be very big and tol is very small, the a_bin and b_bin will not be able to resolve individual bins (then you would have to work with integral types, again checking carefully that their ranges suffice). The solution with loops is a safer one, but if you really need speed, you can invest into optimizing the presented idea. Another option, of course, would be to write a mex extension.
It sounds like what you are trying to do is have an ismember function for use on real valued data.
That is, check for each value B(i) in your vector B whether B(i) is within the tolerance threshold T of at least one value in your vector A
This works out something like the following:
tf = false(1, length(b)); %//the result vector, true if that element of b is in a
t = 0.01; %// the tolerance threshold
for i = 1:length(b)
%// is the absolute difference between the
%//element of a and b less that the threshold?
matches = abs(a - b(i)) < t;
%// if b(i) matches any of the elements of a
tf(i) = any(matches);
end
Or, in short:
t = 0.01;
tf = arrayfun(#(bi) any(abs(a - bi) < t), b);
Regarding avoiding the for loop: while this might benefit from vectorization, you may also want to consider looking at parallelisation if your data is that huge. In that case having a for loop as in my first example can be handy since you can easily do a basic version of parallel processing by changing the for to parfor.
Here is a fully vectorized solution. Note that I would actually recommend the solution given by #Alan, as mine is not likely to work for big datasets.
[X Y]=meshgrid(A,B)
M=abs(X-Y)<tolerance
Now the logical index of elements in a that are within the tolerance can be obtained with any(M) and the index for B is found by any(M,2)
bsxfun to the rescue
>> M = abs( bsxfun(#minus, A, B' ) ); %//' difference
>> M < tolerance
Another way to do what you want is with a logical expression.
Since A and B are vectors of different sizes you can't simply subtract and look for values that are smaller than the tolerance, but you can do the following:
Lmat = sparse((abs(repmat(A,[numel(B) 1])-repmat(B',[1 numel(A)])))<tolerance);
and you will get a sparse logical matrix with as many ones in it as equal elements (within tolerance). You could then count how many of those elements you have by writing:
Nequal = sum(sum(Lmat));
You could also get the indexes of the corresponding elements by writing:
[r,c] = find(Lmat);
then the following code will be true (for all j in numel(r)):
B(r(j))==A(c(j))
Finally, you should note that this way you get multiple counts in case there are duplicate entries in A or in B. It may be advisable to use the unique function first. For example:
A_new = unique(A);