To better explain what I need, here is my first code:
function allpos = f1(x)
allpos=reshape(permute((dec2base(0:power(2,x*x)-1,2)-'0'),[3 2 1]),x,x,[]);
This code does exactly what I need it to. If the users inputs f1(2), it returns every matrix from [0 0; 0 0] to [1 1; 1 1]. However, it also gives me a lot of useless matrices. I only want matrices that are mirrored across the diagonal, with only zeros on the diagonal.
To put more simply, for f1(3), I only want
[0 0 0; 0 0 0; 0 0 0] to [0 1 1; 1 0 1; 1 1 0]. That means that if I run the new f1(3); it will return 8 matrices, not 512.
How do I rewrite the function to do this? I know that it will require some sort of addition of a triangular matrix and its transposed self, but I cant piece it together. Thanks!
It can probably be made more concise but the following does what you ask.
function allpos = f1(x)
N = (x-1)*x / 2;
z = permute(dec2base(0:power(2,N)-1,2)-'0',[3 2 1]);
allpos = zeros(x,x,power(2,N));
idx = repmat(logical(tril(ones(x),-1)),[1,1,power(2,N)]);
allpos(idx) = z(:);
allpos = permute(allpos,[2 1 3]);
allpos(idx) = z(:);
A similar solution to #jodag's one, but more concise...
function allops=f1(x)
allops=zeros(x,x,2^(sum(1:x-1)));
allops(find(triu(ones(x),1))+x^2*(0:2^(sum(1:x-1))-1))=[dec2base(0:2^(sum(1:x-1))-1,2)-'0'].';
allops=allops+permute(allops,[2 1 3])
end
Related
I want to find out row and column number of zeros in 3 dimensional space. Problem is I get output vectors(e.g row) of different length each time, hence dimension error occurs.
My attempt:
a (:,:,1)= [1 2 0; 2 0 1; 0 0 2]
a (:,:,2) = [0 2 8; 2 1 0; 0 0 0]
for i = 1 : 2
[row(:,i) colum(:,i)] = find(a(:,:,i)==0);
end
You can use linear indexing:
a (:,:,1) = [1 2 0; 2 0 1; 0 0 2];
a (:,:,2) = [0 2 8; 2 1 0; 0 0 0];
% Answer in linear indexing
idx = find(a == 0);
% Transforms linear indexing in rows-columns-3rd dimension
[rows , cols , third] = ind2sub(size(a) ,idx)
More on the topic can be found in Matlab's help
Lets assume your Matrix has the format N-by-M-by-P.
In your case
N = 3;
M = 3;
P = 2;
This would mean that the maximum length of rows and coloms from your search (if all entries are zero) is N*M=9
So one possible solution would be
%alloc output
row=zeros(size(a,1)*size(a,2),size(a,3));
colum=row;
%loop over third dimension
n=size(a,3);
for i = 1 : n
[row_t colum_t] = find(a(:,:,i)==0);
%copy your current result depending on it's length
row(1:length(row_t),i)=row_t;
colum(1:length(colum_t),i)=colum_t;
end
However, when you past the result to the next function / script you have to keep in mind to operate on the non-zero elements.
I would go for the vectorized solution of Zep. As for bigger matrices a it is more memory efficient and I am sure it must be way faster.
I have a matrix (89x42) of 0's and 1's that I'd like to multiply combinations of rows together.
For example, for matrix
input = [1 0 1
0 0 0
1 1 0];
and with 2 combinations, I want an output of
output = [0 0 0; % (row1*row2)
1 0 0; % (row1*row3)
0 0 0] % (row2*row3)
Which rows to multiply is dictated by "n Choose 2" (nCk), or all possible combinations of the rows n taken k at a time. In this case k=2.
Currently I am using a loop and it works fine for the 89C2 combinations of rows, but when I run it with 89C3 it takes far too long too run.
What would be the most efficient way to do this program so I can do more than 2 combinations?
You can do it using nchoosek and element-wise multiplication.
inp = [1 0 1; 0 0 0; 1 1 0]; %Input matrix
C = nchoosek(1:size(inp,1),2); %Number of rows taken 2 at a time
out = inp(C(:,1),:) .* inp(C(:,2),:); %Multiplying those rows to get the desired output
Several things you can do:
Use logical ("binary") arrays (or even sparse logical arrays) instead of double arrays.
Use optimized combinatorical functions.
bitand or and instead of times (where applicable).
Vectorize:
function out = q44417404(I,k)
if nargin == 0
rng(44417404);
I = randi(2,89,42)-1 == 1;
k = 3;
end
out = permute(prod(reshape(I(nchoosek(1:size(I,1),k).',:).',size(I,2),k,[]),2),[3,1,2]);
I'm unsure how to phrase the question, but I think an example will help. Suppose I have a vector y = [3;1;4;1;6]. I want to create the matrix Y =
[0 0 1 0 0 0;
1 0 0 0 0 0;
0 0 0 1 0 0;
1 0 0 0 0 0;
0 0 0 0 0 1]
↑ ↑ ↑ ↑ ↑ ↑
1 2 3 4 5 6
where the element on each column is one or zero corresponding to the value in the vector.
I found that I could do it using
Y = []; for k = 1:max(y); Y = [Y (y==k)]; end
Can I do it without a for loop (and is this method more efficient if y has thousands of elements)?
Thanks!
Your method is not efficient because you're growing the size of Y in the loop which is not a good programming practice. Here is how your code can be fixed:
Ele = numel(y);
Y= zeros(Ele, max(y));
for k = 1:Ele
Y (k,y(k))= 1;
end
And here is an alternative approach without a loop:
Ele = numel(y); %Finding no. of elements in y
Y= zeros(Ele, max(y)); % Initiailizing the matrix of the required size with all zeros
lin_idx = sub2ind(size(Y), 1:Ele, y.'); % Finding linear indexes
Y(lin_idx)=1 % Storing 1 in those indexes
You can use bsxfun:
result = double(bsxfun(#eq, y(:), 1:max(y)));
If you are running the code on Matlab version R2016b or later, you can simplify the syntax to
result = double(y(:)==(1:max(y)));
Another approach, possibly more efficient, is to fill in the values directly using accumarray:
result = accumarray([(1:numel(y)).' y(:)], 1);
I found another solution:
E = eye(max(y));
Y = E(y,:);
Another solution:
Y = repmat(1:max(y), size(y)) == repmat(y, 1, max(y))
I've a series of coordinates (i,j) and I want to loop through each one.
For example
A = ones(3,3);
i = [1 2 3];
j = [3 2 1];
I tried with this but it doesn't work:
for (i = i && j = j)
A(i,j) = 0;
end
I also tried this but it doens't work as expected:
for i = i
for j = j
A(i,j) = 0;
end
end
Desired result:
A =
1 1 0
1 0 1
0 1 1
Although A is a matrix in this example, I am working with table data.
The correct syntax to do what you want is:
A = ones(3,3);
i = [1 2 3];
j = [3 2 1];
for ii = 1:length( i )
A( i(ii) , j(ii) ) = 0;
end
Essentially you loop through each element and index i and j accordingly using ii. ii loops through 1..3 indexing each element.
This will give the a final result below.
>> A
A =
1 1 0
1 0 1
0 1 1
While this works and fixes your issue, I would recommend rayryeng's alternate solution with conversions if you don't have more complex operations involved.
Though this doesn't answer your question about for loops, I would avoid using loops all together and create column-major linear indices to access into your matrix. Use sub2ind to help facilitate that. sub2ind takes in the size of the matrix in question, the row locations and column locations. The output will be an array of values that specify the column-major locations to access in your matrix.
Therefore:
A = ones(3); i = [1 2 3]; j = [3 2 1]; %// Your code
%// New code
ind = sub2ind(size(A), i, j);
A(ind) = 0;
Given that you have a table, you can perhaps convert the table into an array, apply sub2ind on this array then convert the result back to a table when you're done. table2array and array2table are useful tools here. Given that your table is stored in A, you can try:
Atemp = table2array(A);
ind = sub2ind(size(Atemp), i, j);
Atemp(ind) = 0;
A = array2table(Atemp);
im getting a vertcat error in my for loop, i have looked about for a solution but i cant seem to find one that has a matrix in the loop. It also appears to solve the loop once then get stuck the second time round. this is my code:
the error is at matrix A, any help would be greatly appreciated, thanks.
phi=1:1:89;
for i=1:length(phi)
m=cosd(phi(1:i));
l=sind(phi(1:i));
%the following calculates k tilde ratio for use in solving of equations
r= U1/U2; %velocity ratio
Kratio = ((r*(mach2/(1-mach2^2)))*(-m*mach2 + l*sqrt((m.^2/l.^2)-(((1/r)^2)*
((1/mach2^2)-1)))));
alpha = (A2^2/(gamma*U1^2))*(Kratio/(m-(Kratio*(1/r))));
beta= (A2^2/(gamma*U1^2))*(l/(m-(Kratio*(1/r))));
%from boundary conditions
B1= (((gamma-1)*(mach1^2))-2)/((gamma+1)*(mach1^2));
B2= 2/((gamma+1)*mach1^2);
C1=4/(((gamma-1)*mach1^2)+2);
C2= -(((gamma-1)*mach1^2)+4)/(((gamma-1)*mach1^2)+2);
D1= (4*gamma*mach1^2)/((2*gamma*mach1^2)-(gamma-1));
D2=-((2*gamma*mach1^2)/((2*gamma*mach1^2)-(gamma-1)));
E1= (2*(mach1^2-1))/((gamma+1)*mach1^2);
%matrix to be solved for unknown coefficients
matrixA= [1 0 0 -alpha 0 0 0; 0 ((m*r)) 0 0 l 0 0; 0 0 1 -beta 0 0 0; 1 1 0 0 0
(B1-1) 0; 0 0 0 1/gamma 0 C1 1; 0 0 0 1 0 D1 0; 0 0 1 0 1 ((E1*l)/m) 0];-->error here
matrixB= [0 ; 0 ; 0 ; -B2*Ae+B1*l*Av ; C1*l*Av-C2*Ae ; D1*l*Av-D2*Ae; -m*Av];
format long
coefficients= matrixA\matrixB;
i=sqrt(-1);
t=0;
F=coefficients(1,1);
G=coefficients(2,1);
H=coefficients(3,1);
K=coefficients(4,1);
I=coefficients(5,1);
L=coefficients(6,1);
Q=coefficients(7,1);
% assumes k=1 for equation Kratio,t=0 for this case (test)
%N=201;
%x=zeros(N);
%for j=1:N
x=20;
x1=-20;
%end
%for j=1:N
y=0;
y2=0;
%upstream and downstream conditions
%plots the graph for fixed t
% k has been set to 2
%entropy modes
%vorticity modes
%plot for upstream KE
u1prime= l*Av*exp(k*i*(m*x1+l*y2-U1*m*t));
v1prime= -m*Av*exp(k*i*(m*x1+l*y2-U1*m*t));
KE1= u1prime.*conj(u1prime)+v1prime.*conj(v1prime);
%plot for downstream KE (kinetic engery)
u2prime2=F*exp(k*i*Kratio*x+k*i*l*y-k*i*U1*m*t)+G*exp((k*i*(m*r*x+l*y-U1*m*t)));
v2prime2=H*exp(k*i*Kratio*x+k*i*l*y-k*i*U1*m*t)+I*exp((k*i*(m*r*x+l*y-U1*m*t)));
KE=u2prime2.*conj(u2prime2)+v2prime2.*conj(v2prime2);
KEnorm=(KE)/KE1
end
Your problem arises from (m*r) (and another one will arise with l in matrixB).
m and l grow inside the loop:
m=cosd(phi(1:i));
l=sind(phi(1:i));
It's up to you to figure out which portion of m and l you want to use after the first iteration.
As Dan pointed out, the route to debug this is to set a breakpoint in the line that gives the error. Once you get to it, check all the variables in your matrix for their size.
One last comment: I had to assume the following variables:
U1 = 1.0;
U2 = 0.5;
mach2 = 0.3;
mach1 = 0.5;
A2 = 0.6;
gamma = 1.4;
Ae = 1;
Av = 1;
k = 1;
Next time, please consider providing a minimal working example, that upon copy/paste will regenerate your problem.
EDIT
If you attempt to fix your code, consider the following steps:
As Divakar suggested, do not use i as the loop counter, when you need it as the imaginary unit. Therefore, replace all instances of the loop counter with ii (take your time doing this, you do not want to overlook one instance).
Next, you have two choices:
either, replace m and l with this:
m=cosd(phi(ii));
l=sind(phi(ii));
that way, both m and l will remain scalars
or, replace every instance of m and l with m(ii) and l(ii) respectively
whichever you do, be consistent.