Im writing currently rewriting a Matlab script in C. When i get to the last few lines of the Matlab script a for loop is executed and it iterates through an array. Since i am trying to rewrite the program in C the slicing notation in the Matlab script is confusing me. I have attached the line of code that is troubling me below.
How would i write this line of code in a nested for loop indexing with i and j only, since you cant slice in c obviously. just for reference u = 1, Ubc is 2D array of size (NX+2, NY+2). Where NX = NY = 40.
Below is the line of code in Matlab i need to translate to for loop indexing.
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
% First the i interfaces
F = 0.5* u *( Ubc(2:Nx+2,2:Ny+1) + Ubc(1:Nx+1,2:Ny+1))
- 0.5*abs(u)*( Ubc(2:Nx+2,2:Ny+1) - Ubc(1:Nx+1,2:Ny+1));
You can calculate the same in a loop as
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
F = zeros(Nx + 1, Ny);
for z1 = 1 : Nx + 1
for z2 = 1 : Ny
F(z1, z2) = 0.5* u *( Ubc(z1 + 1, z2 + 1) + Ubc(z1, z2 + 1))
- 0.5*abs(u)*( Ubc(z1 + 1, z2 + 1) - Ubc(z1, z2 + 1));
end
end
You shouldn't use i and j as loop index in Matlab. Both are the imaginary unit.
Related
I have 2 matrices defined as follows:
A=[1 2;3 4]
B=[1 4; 5 3]
Then I define Aensem, Bensem and Gensem like this:
Arow=A(:);
Brow=B(:);
Aensem=repmat(Arow,1,10);
Bensem=repmat(Brow,1,10);
G=A*B;
Grow=G(:);
Gensem=repmat(Grow,1,10);
I need to create a function that can calculate any Gensem-like arrays directly from Aensem and Bensem. I only have knowledge of Aensem and Bensem. I tried the following method, but it's not working:
function ret = mat_mult(v1, v2, r)
ret = zeros(size(v1));
for i = 1:2*r.c.M
for j = 1:2*r.c.M
sum = 0;
for k = 1:2*r.c.M
sum = sum + ...
v1(idx1(i,k,r),:) .* v2(idx1(k,j,r),:);
ret(idx1(i,j,r),:)=sum;
end
end
end
end
If I understand your question correctly, you want to calculate Gensem directly from Aensem and Bensem. This can be done as follows:
A_ = reshape(Aensem(:, 1), 2, 2); % extract A from Aensem
B_ = reshape(Bensem(:, 1), 2, 2); % extract B from Bensem
G_ = A_*B_; % calculate G based on the extracted A and B
Gensem_ = repmat(G_(:),1,10); % build Gensem
[r,c] = size(x);
[m,n] = size(y);
h = rot90(y, 2);
center = floor((size(h)+1)/2);
Rep = zeros(r + m*2-2, c + n*2-2);
return
for x1 = m : m+r-1
for y1 = n : n+r-1
Rep(x1,y1) = x(x1-m+1, y1-n+1);
end
end
B = zeros(r+m-1,n+c-1);
for x1 = 1 : r+m-1
for y1 = 1 : n+c-1
for i = 1 : m
for j = 1 : n
B(x1, y1) = B(x1, y1) + (Rep(x1+i-1, y1+j-1) * h(i, j));
end
end
end
end
Con=conv2(Rep,h);
I have this code for 2d convolution.But Con and B are different(last column of correct convolution(=Con) does not exist in B,and other elements also differ.I cant understand what i do wrong.
This question already has answers here:
Numerical derivative of a vector
(3 answers)
Closed 7 years ago.
I have two arrays: x and y. In practice, y is dependent on x, but both arrays are measured values. I would like to obtain the derivative of y with respect to x. If x were uniformly spaced (i.e. x=[1 2 3 4 5]), I could do something with diff like this:
h = 0.001;
x = -pi:h:pi;
f = sin(X);
y = diff(f)/h;
However, x is not uniformly spaced (i.e. x=[1 1.9 2.8 4.1]). How can I obtain the partial derivative of this data set?
A good way to do it is gradient,
dydx = gradient(y, x);
I like it because it returns a vector which is the same length as x and y. The downside though, is it's first order accurate. This can sometimes be a problem, a fix could be to write your own,
x = unique([linspace(0, 2*pi, 50), logspace(0, log10(2*pi), 50)]);
y = cos(x) ;
subplot(2,1,1) ;
plot(x, Gradient(y, x), x, gradient(y,x), x, -sin(x));
legend('2^{nd} order', '1^{st} order', 'exact') ;
subplot(2,1,2) ;
plot(x, Gradient(y, x) + sin(x), x, gradient(y,x) + sin(x));
legend('2^{nd} order - exact', '1^{st} order - exact')
With Gradient being
function dydx = Gradient(y,x)
y = y(:);
p = x(3:end) - x(2:end-1);
p = p(:);
m = x(2:end-1) - x(1:end-2);
m = m(:);
p1 = x(2) - x(1);
p2 = x(3) - x(1);
m1 = x(end) - x(end-1);
m2 = x(end) - x(end-2);
dydx = reshape([ ((-p1^2 + p2^2)*y(1) - p2^2*y(2) + p1^2*y(3))/(p1*(p1 - p2)*p2);
((-m.^2 + p.^2).*y(2:end-1) - p.^2.*y(1:end-2) + m.^2.*y(3:end))./(m.*p.*(m + p));
((m1^2 - m2^2)*y(end) + m2^2*y(end-1) - m1^2*y(end-2))/(m1^2*m2 - m1*m2^2) ...
], size(x));
end
Edit:
Improved it for multidimensional array and constant spacing support
function dydx = Gradient(y,x)
if length(y) < 3
dydx = gradient(y,x);
return
end
[~, n] = max(size(y));
N = ndims(y);
i = repmat({':'},1,N-1);
y = permute(y, [n, 1:n-1, n+1:N]);
if isscalar(x)
%"x" is actually a spacing value
p = x;
m = x;
p1 = x;
p2 = x;
m1 = x;
m2 = x;
else
if isvector(x)
x = repmat(x(:), size(y(1, i{:})));
else
x = permute(x, [n, 1:n-1, n+1:N]);
end
if all(size(x) ~= size(y))
error('Sizes of arrays must be the same.')
end
p = x(3:end, i{:}) - x(2:end-1, i{:});
m = x(2:end-1, i{:}) - x(1:end-2, i{:});
p1 = x(2, i{:}) - x(1, i{:});
p2 = x(3, i{:}) - x(1, i{:});
m1 = x(end, i{:}) - x(end-1, i{:});
m2 = x(end, i{:}) - x(end-2, i{:});
end
dydx = ipermute([ ((-p1.^2 + p2.^2).*y(1,i{:}) - p2.^2.*y(2,i{:}) + p1.^2.*y(3,i{:}))./(p1.*(p1 - p2).*p2);
((-m.^2 + p.^2).*y(2:end-1,i{:}) - p.^2.*y(1:end-2,i{:}) + m.^2.*y(3:end,i{:}))./(m.*p.*(m + p));
((m1.^2 - m2.^2).*y(end,i{:}) + m2.^2.*y(end-1,i{:}) - m1.^2.*y(end-2,i{:}))./(m1.^2.*m2 - m1.*m2.^2) ...
], [n, 1:n-1, n+1:N]);
end
I have the antenna array factor expression here:
I have coded the array factor expression as given below:
lambda = 1;
M = 100;N = 200; %an M x N array
dx = 0.3*lambda; %inter-element spacing in x direction
m = 1:M;
xm = (m - 0.5*(M+1))*dx; %element positions in x direction
dy = 0.4*lambda;
n = 1:N;
yn = (n - 0.5*(N+1))*dy;
thetaCount = 360; % no of theta values
thetaRes = 2*pi/thetaCount; % theta resolution
thetas = 0:thetaRes:2*pi-thetaRes; % theta values
phiCount = 180;
phiRes = pi/phiCount;
phis = -pi/2:phiRes:pi/2-phiRes;
cmpWeights = rand(N,M); %complex Weights
AF = zeros(phiCount,thetaCount); %Array factor
tic
for i = 1:phiCount
for j = 1:thetaCount
for p = 1:M
for q = 1:N
AF(i,j) = AF(i,j) + cmpWeights(q,p)*exp((2*pi*1j/lambda)*(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i))));
end
end
end
end
How can I vectorize the code for calculating the Array Factor (AF).
I want the line:
AF(i,j) = AF(i,j) + cmpWeights(q,p)*exp((2*pi*1j/lambda)*(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i))));
to be written in vectorized form (by modifying the for loop).
Approach #1: Full-throttle
The innermost nested loop generates this every iteration - cmpWeights(q,p)*exp((2*pi*1j/lambda)*(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i)))), which are to summed up iteratively to give us the final output in AF.
Let's call the exp(.... part as B. Now, B basically has two parts, one is the scalar (2*pi*1j/lambda) and the other part
(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i))) that is formed from the variables that are dependent on
the four iterators used in the original loopy versions - i,j,p,q. Let's call this other part as C for easy reference later on.
Let's put all that into perspective:
Loopy version had AF(i,j) = AF(i,j) + cmpWeights(q,p)*exp((2*pi*1j/lambda)*(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i)))), which is now equivalent to AF(i,j) = AF(i,j) + cmpWeights(q,p)*B, where B = exp((2*pi*1j/lambda)*(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i)))).
B could be simplified to B = exp((2*pi*1j/lambda)* C), where C = (xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i))).
C would depend on the iterators - i,j,p,q.
So, after porting onto a vectorized way, it would end up as this -
%// 1) Define vectors corresponding to iterators used in the loopy version
I = 1:phiCount;
J = 1:thetaCount;
P = 1:M;
Q = 1:N;
%// 2) Create vectorized version of C using all four vector iterators
mult1 = bsxfun(#times,sin(thetas(J)),cos(phis(I)).'); %//'
mult2 = bsxfun(#times,sin(thetas(J)),sin(phis(I)).'); %//'
mult1_xm = bsxfun(#times,mult1(:),permute(xm,[1 3 2]));
mult2_yn = bsxfun(#times,mult2(:),yn);
C_vect = bsxfun(#plus,mult1_xm,mult2_yn);
%// 3) Create vectorized version of B using vectorized C
B_vect = reshape(exp((2*pi*1j/lambda)*C_vect),phiCount*thetaCount,[]);
%// 4) Final output as matrix multiplication between vectorized versions of B and C
AF_vect = reshape(B_vect*cmpWeights(:),phiCount,thetaCount);
Approach #2: Less-memory intensive
This second approach would reduce the memory traffic and it uses the distributive property of exponential - exp(A+B) = exp(A)*exp(B).
Now, the original loopy version was this -
AF(i,j) = AF(i,j) + cmpWeights(q,p)*exp((2*pi*1j/lambda)*...
(xm(p)*sin(thetas(j))*cos(phis(i)) + yn(q)*sin(thetas(j))*sin(phis(i))))
So, after using the distributive property, we would endup with something like this -
K = (2*pi*1j/lambda)
part1 = K*xm(p)*sin(thetas(j))*cos(phis(i));
part2 = K*yn(q)*sin(thetas(j))*sin(phis(i));
AF(i,j) = AF(i,j) + cmpWeights(q,p)*exp(part1)*exp(part2);
Thus, the relevant vectorized approach would become something like this -
%// 1) Define vectors corresponding to iterators used in the loopy version
I = 1:phiCount;
J = 1:thetaCount;
P = 1:M;
Q = 1:N;
%// 2) Define the constant used at the start of EXP() call
K = (2*pi*1j/lambda);
%// 3) Perform the sine-cosine operations part1 & part2 in vectorized manners
mult1 = K*bsxfun(#times,sin(thetas(J)),cos(phis(I)).'); %//'
mult2 = K*bsxfun(#times,sin(thetas(J)),sin(phis(I)).'); %//'
%// Perform exp(part1) & exp(part2) in vectorized manners
part1_vect = exp(bsxfun(#times,mult1(:),xm));
part2_vect = exp(bsxfun(#times,mult2(:),yn));
%// Perform multiplications with cmpWeights for final output
AF = reshape(sum((part1_vect*cmpWeights.').*part2_vect,2),phiCount,[])
Quick Benchmarking
Here are the runtimes with the input data listed in the question for the original loopy approach and proposed approach #2 -
---------------------------- With Original Approach
Elapsed time is 358.081507 seconds.
---------------------------- With Proposed Approach #2
Elapsed time is 0.405038 seconds.
The runtimes suggests a crazy performance improvement with Approach #2!
The basic trick is to figure out what things are constant, and what things depend on the subscript term - and therefore are matrix terms.
Within the sum:
C(n,m) is a matrix
2π/λ is a constant
sin(θ)cos(φ) is a constant
x(m) and y(n) are vectors
So the two things I would do are:
Expand the xm and ym into matrices using meshgrid()
Take all the constant term stuff outside the loop.
Like this:
...
piFactor = 2 * pi * 1j / lambda;
[xgrid, ygrid] = meshgrid(xm, ym); % xgrid and ygrid will be size (N, M)
for i = 1:phiCount
for j = 1:thetaCount
xFactor = sin(thetas(j)) * cos(phis(i));
yFactor = sin(thetas(j)) * sin(phis(i));
expFactor = exp(piFactor * (xgrid * xFactor + ygrid * yFactor)); % expFactor is size (N, M)
elements = cmpWeights .* expFactor; % elements of sum, size (N, M)
AF(i, j) = AF(i, j) + sum(elements(:)); % sum and then integrate.
end
end
You could probably figure out how to vectorise the outer loop too, but hopefully that gives you a starting point.
The below code is supposed to calculate some values and place them in incremental places in the numpy.zeros() array. The calculations all perform correctly but the array stays as just zeros. I could be missing something obvious so apologies if I am.
n = 256
lam = l
a = numpy.zeros([(len(z[0]) * len(z[:,0]) + n + 1), (n + len(z[0]))])
b = numpy.zeros([numpy.size(a, 0), 1])
#data fitting equations
k = 0
for i in range(len(z[0])):
for j in range(len(z[:,0])-1):
wij = smoother(z[j][i] + lam)
a[k][(z[j][i]+lam)] = float(wij)
print a[k][(z[j][i]+lam)]
a[k][n+j] = float(-wij)
b[k][0] = float(-wij * B[j])
k = k + 1
Thanks,
Tom
Answer supplied by Jaime works fine. Use
a[1, 2]
rather than
a[1][2]