I have two Matrices: Matrix 1: A, that is the Matrix I have in the beginning and Matrix 2: B that has some values from A permuted. Both are filled with only ones and zeros (mainly zeros)
for example
0 0 0 0 0 1
A = 0 1 0 and B = 0 0 0
0 0 0 0 0 0
where I move the value 1 from the middle of matrix A to the top right corner in matrix B. I can do this manually by multiplicating with the Transformation-matrices T1 and T2.
for the example above:
0 1 0 0 0 0
T1 = 0 0 0 and T2 = 0 0 1 such that P1 * A * P2 = B
0 0 0 0 0 0
How can I calculate these two Transformation-matrices P1 and P2 with Matlab really fast (for matrices > 5000x5000) by only knowing matrix A and B?
The goal is to move some of the ones with every step on matrix A. As I have some other Matrices that act like layers, I would like to move them the same way, so I'd like to get T1 and T2 so I can change them the same way.
So the problem is that I have an island, that I get from GoogleMaps, that I convert in 0 (water) and 1 (land) and I randomly put People on that Map M. Then I randomly set the position of some people where M has a one. These people are set on matrix A with a one, rest is zero. The people move, the new position is given by Matrix B. While not all people are infected by zombies yet, I have a vector, that defines a subMatrix, where the zombies are. This little Matrix is the important one, so I move my zombie and some other attributes, that the zombie has (they are defined by other Matrices, I call them lazer Matrices). So I only want the changes of the Zombiematrix tracked (for that I need the Transformation Matrix), so that all layer matrices that have the attributes of the zombie Submatrix are moved the same way. The ZombieMatrix then grows bigger and bigger, the more people are infected. To save time, I look for a subMatrix that contains all the Zombies by each step and then perform the Transformationmatrix on this subMatrix.
I know that sounds all fuzzy, that's why I just asked the way above the line.
Since your problem is nonlinear it can have multiple solutions, from which the comment of #knedlsepp. For this reason I think that resorting to a genetic algorithm might be a good option, naturally without looking at the performances...
Let us reformulate your problem as an optimization one
Here we will adopt the Frobenius norm.
Then the code would look like
%// Build the test matrices
A = [0 0 0 ; 0 1 0 ; 0 0 0];
B = [0 0 1 ; 0 0 0 ; 0 0 0];
n = size(A, 1);
%// Define the optimization problem.
nvars = 2*n^2;
lb = zeros(nvars, 1);
ub = ones(nvars, 1);
intCon = 1:nvars;
options = gaoptimset();
%// Solve the problem.
[t,err,exitflag] = ga(#(t) fitnessfcn(t, A, B, n), ...
nvars, [], [], [], [], lb, ub, [], intCon, options);
%// Retrieve the solution
T1 = reshape(t(1:n^2), n, n);
T2 = reshape(t(n^2+1:end), n, n);
and fitnessfcn is
function err = fitnessfcn(t, A, B, n)
T1 = reshape(t(1:n^2), n, n);
T2 = reshape(t(n^2+1:end), n, n);
E = T1*A*T2-B;
err = norm(E, 'fro');
I hope that by playing with the options you can apply this code to more realistic cases.
Related
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
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 am trying to teach myself how about Finite Element Methods.
All of my code is adapted from the following link pages 16-20
http://homepages.cae.wisc.edu/~suresh/ME964Website/M964Notes/Notes/introfem.pdf
I am programming along in Matlab to perform a finite element analysis on a single 8 node cube element. I have defined the xi,eta,zeta local axes (we can think about this as x, y, z for now), so I get the following shape functions:
%%shape functions
zeta = 0:.01:1;
eta = 0:.01:1;
xi = 0:.01:1;
N1 = 1/8*(1-xi).*(1-eta).*(1-zeta);
N2 = 1/8*(1+xi).*(1-eta).*(1-zeta);
N3 = 1/8*(1+xi).*(1+eta).*(1-zeta);
N4 = 1/8*(1-xi).*(1+eta).*(1-zeta);
N5 = 1/8*(1-xi).*(1-eta).*(1+zeta);
N6 = 1/8*(1+xi).*(1-eta).*(1+zeta);
N7 = 1/8*(1+xi).*(1+eta).*(1+zeta);
N8 = 1/8*(1-xi).*(1+eta).*(1+zeta);
The [N] Matrix is to be arranged like this according to the text I am reading:
%N Matrix
N= [N1 0 0 N2 0 0 N3 0 0 N4 0 0 N5 0 0 N6 0 0 N7 0 0 N8 0 0;
0 N1 0 0 N2 0 0 N3 0 0 N4 0 0 N5 0 0 N6 0 0 N7 0 0 N8 0;
0 0 N1 0 0 N2 0 0 N3 0 0 N4 0 0 N5 0 0 N6 0 0 N7 0 0 N8];
To find the [B] matrix i have to use the following [D] matrix:
%%Del Matrix for node i
%[ d/dx 0 0
% 0 d/dy 0
% 0 0 d/dz . . .
% d/dy d/dx 0
% 0 d/dz d/dy
% d/dz 0 d/dx ]
which is an operator to go on [N]. (B=DN)
Later on, as the text shows, I will be making calculations involving integrals of this [B] matrix over the volume of this element.
So, my question is, how can I store these polynomial shape functions in a matrix, operate on them with differentiation, and then integrate them numerically. I can tell with the way I have this set up right now, that it wont work because I have defined the functions as a vector over an interval [0,1] and then storing these vectors in the [N] matrix. Then using diff() function to differentiate appropriately to find the [B] matrix.
But since the matrix elements of [B] are now vectors over an interval [0,1] I think that is going to cause problems. How would you guys go about these calculations described in the textbook I posted above?
Solved my problem using anonymous functions and storing the polynomials in a symbolic matrix. example:
syms xi eta zeta
N1= ... %type out in terms of xi eta and zeta
.
.
.
dN1dXi = diff(N1,xi) %symbolic differentiation with respect to xi
can also perform symbolic integration when needed:
intN1 = int(N1,xi,lowerLimit,upperLimit) %symbolic integration with respect to xi
and when ready to substitute in actual values to evaluate the symbolic functions:
subs(N1,{xi,eta,zeta},{value1,value2,value3})
You should check page 24 about how to map from a parametric domain ([0,1]^) to the physical domain.
Although I think you can do as you said, using symbolic. I think symbolic calculation in Matlab is very time-consuming.
I would go for derivate N manually and store as dN, and use it when need it.
Regards,
German
after you have the shape functions you need to substitute it in the stiffness matrix, the stiffness matrix should be 24x24 as you have 24 degrees of freedom. to solve you need to build a linear system (Ax=b), the right hand side is based on the PDE you are solving and you have to include neuman boundary conditions in the right hand side plus the source term. In python for 2d element (4 DOF) will be like:
def shapefxncoef (Valxy):
#creating a temporary metrix to store zeros and get the size of the shape
#function matrix.
n_temp = np.zeros((4,4))
#filling the values of the matrix with a loop.
for i in range(4):
#the values used in the matrix are from the Valxy x and y components.
xi = Valxy [0, i];
yi = Valxy [1, i];
n_temp[i, 0] = 1;
n_temp[i, 1] = xi;
n_temp[i, 2] = yi;
n_temp[i, 3] = xi*yi;
#this gives an identity matrix and the stiffness matric can be derived
#if we take the inverse.
n = np.linalg.inv(n_temp);
return n;
def N (Valxy, x, y):
n = shapefxncoef (Valxy);
res = n[0, :] + n[1, :]*x + n[2, :]*y + n[3, :]*x*y;
return res;
def Be (Valxy, x, y):
res = np.zeros ((2,4));
res_temp = shapefxncoef (Valxy);
for i in range (4):
res_tempi = res_temp[:, i];
dNix = res_tempi[1] + res_tempi[3]*y;
dNiy = res_tempi[2] + res_tempi[3]*x;
res[0, i] = dNix;
res[1, i] = dNiy;
return res;
def Ke (Valxy, conduct):
a = lambda x, y: conduct * np.dot ((Be(Valxy, x, y)).T, Be(Valxy, x, y));
k = intr.integrateOnQuadrangle (Valxy.T, a, np.zeros((4,4)));
return k;
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.
I need to generate a random matrix of K columns and N rows containing ones and zeroes, such that:
a) Each row contains exactly k ones.
b) Each row is different from the other (combinatorics imposes that if N > nchoosek(K, k) there will be nchoosek(K,k) rows).
Assume I want N = 10000 (out of all the possible nchoosek(K, k) = 27405 combinations), different 1×K vectors (with K = 30) containing k (with k = 4) ones and K - k zeroes.
This code:
clear all; close
N=10000; K=30; k=4;
M=randi([0 1],N,K);
plot(sum(M,2)) % condition a) not satisfied
does not satisfy neither a) nor b).
This code:
clear all; close;
N=10000;
NN=N; K=30; k=4;
tempM=zeros(NN,K);
for ii=1:NN
ttmodel=tempM(ii,:);
ttmodel(randsample(K,k,false))=1; %satisfies condition a)
tempM(ii,:)=ttmodel;
end
Check=bi2de(tempM); %from binary to decimal
[tresh1,ind,tresh2] = unique(Check);%drop the vectors that appear more than once in the matrix
M=tempM(ind,:); %and satisfies condition b)
plot(sum(M,2)) %verify that condition a) is satisfied
%Effective draws, Wanted draws, Number of possible combinations to draw from
[sum(sum(M,2)==k) N nchoosek(K,k) ]
satisfies condition a) and partially condition b). I say partially because unless NN>>N the final matrix will contain less than N rows each different from each other.
Is there a better and faster way (that possible avoids the for cycle and the need of having NN>>N) to solve the problem?
First, generate N unique k-long permutations of the positions of ones:
cols = randperm(K, N);
cols = cols(:, 1:k);
Then generate the matching row indices:
rows = meshgrid(1:N, 1:k)';
and finally create the sparse matrix with:
A = sparse(rows, cols, 1, N, K);
To obtain the full form of the matrix, use full(A).
Example
K = 10;
k = 4;
N = 5;
cols = randperm(K, N);
cols = cols(:, 1:k);
rows = meshgrid(1:N, 1:k)';
A = sparse(rows, cols , 1, N, K);
full(A)
The result I got is:
ans =
1 1 0 0 0 0 0 1 0 1
0 0 1 1 0 1 0 0 0 1
0 0 0 1 1 0 1 0 1 0
0 1 0 0 0 0 1 0 1 1
1 1 1 0 0 1 0 0 0 0
This computation should be pretty fast even for large values of K and N. For K = 30, k = 4, N = 10000 the result was obtained in less than 0.01 seconds.
You could use randperm(n) to generate random sequences of integers from 1 to n, and store the nonrepeated sequences as rows in a matrix M until size(unique(M,'rows'),1)==size(M,1). Then you could use M to index a logical matrix with the appropriate number of true values in each row.
If you have enough memory for nchoosek(K,k) integers, build an array of those, use a partial Fisher-Yates shuffle to get a proper uniformly random subset of N of those. Now, given the array of N integers, interpret each as the rank of the combination representing each row of your final array. If you use colexicographical ordering of combinations, computing the combination from a rank is pretty simple (though it uses lots of binomial combination functions, so it pays to have a fast one).
I'm not a Matlab guy, but I've done things similar to this in C. This code, for example:
for (i = k; i >= 1; --i) {
while ((b = binomial(n, i)) > r) --n;
buf[i-1] = n;
r -= b;
}
will fill the array buf[] with indices from 0 to n-1 for the rth combination of k out of n elements in colex order. You would interpret these as the positions of the 1s in your row.