How can I compute this sum without a for loop? - arrays

In particular I'm interested in the summatory. It uses k two times, but using sum I don't know how to obtain the index.
Considering only the summatory:
summatory = sum( L(i, 1:j-1) * L(j, 1:j-1) );
is obviosly wrong.
How can I do it without a for loop?

That's an inner product between an 1x(j-1) vector and a (j-1)x1 vector:
krange = 1:j-1;
summatory = L(i, krange) * L(j, krange)';
Your code would also have worked (now that you've fixed the syntax), if you used the element-wise product operator .* instead of the matrix product *.

Either compute the inner product with vector algebra (i.e. v*v' as demonstrated by #BenVoigt), or use sum, but with the element-wise product (.*):
summatory = sum( L(i, 1:j-1) .* L(j, 1:j-1) );

Related

Summing a fortran array with mask

I have a fortran array a(i,j). I wish to sum it on dimension 2(j) with a mask that j is not equal to i.
i.e,
a1=0
do j=1,n
if(j.ne.i) then
a1=a1+a(i,j)
endif
enddo
What is the way of doing this using the intrinsic sum function in fortran as I found the intrinsic to be much faster than the explicit loop.
I thought of trying sum(a(i,:),j.ne.i), but this is naturally giving error. Also if one can suggest how to only some the values of a(i,:) where abs(a(i,j)) is greater than, say 0.01, it would be helpful.
You can easily avoid any branching for the off-diagonal case. It should be much faster than creating any mask array and checking the mask. Branching (conditional jumps) is costly even when branch prediction can be very efficient.
do j=1,n
do i = 1,j-1
a1=a1+a(i,j)
end do
do i = j+1,n
a1=a1+a(i,j)
end do
end do
If you need your code to be fast and not short, you should test this kind of approach. In my tests it is much faster.
To answer your last question, you can use the WHERE construct to build a mask. For example,
logical :: y(3,3) = .false.
real x(3,3)
x = 1
x(1,1) = 0.1
x(2,2) = 0.1
x(3,3) = 0.1
print * , sum(x)
where(abs(x) > 0.25) y = .true.
print *, sum(x,y)
end
Whether this is better than nested do-loops is questionable.
I find that summing the whole array then subtracting sum of diagonal elements can be 2x faster.
a1 = 0
do i = 1, n
a1 = a1 + a(i,i)
end do
a1 = sum(a) - a1
end do

Calculating Euclidean distance of pairs of 3D points in matlab

I have an Nx3 array that contains N 3D points
a1 b1 c1
a2 b2 c2
....
aN bN cN
I want to calculate Euclidean distance in a NxN array that measures the Euclidean distance between each pair of 3D points. (i,j) in result array returns the distance between (ai,bi,ci) and (aj,bj,cj). Is it possible to write a code in matlab without loop ?
The challenge of your problem is to make a N*N matrix and the result should return in this matrix without using loops.
I overcome this challenge by giving suitable dimension to Bsxfun function. By default X and ReshapedX should have the same dimensions when we call bsxfun function. But if the size of the matrixes are not equal and one of them has a singleton (equal to 1) dimension, the matrix is virtually replicated along that dimension to match the other matrix. Therefore, it returns N*3*N matrix which provides subtraction of each 3D point from the others.
ReshapedX = permute(X,[3,2,1]);
DiffX = bsxfun(#minus,X,ReshapedX);
DistX =sqrt(sum(DiffX.^2,2));
D = squeeze(DistX);
Use pdist and squareform:
D = squareform( pdist(X, 'euclidean' ) );
For beginners, it can be a nice exercise to compute the distance matrix D using bsxfun (hover to see the solution).
elemDiff = bsxfun( #minus, permute(X,[ 1 3 2 ]), permute(X, [ 3 1 2 ]) );
D = sqrt( sum( elemDiff.^2, 3 ) );
To complete the comment of Divakar:
x = rand(10,3);
pdist2(x, x, 'euclidean')

Vectorize quadratic expansion

I have a matrix X with vectors in n columns. In my case this is a series of vectors in time (column 1 is t1, column 2 is t2 ...). I would like to return a new matrix Y such that for each X(:,i)
Y(:,i) = [ X(1,i)^2, X(1,i)*X(2,i), ... X(n-1,i)*X(n,i), X(n,i)^2 ];
Currently I do this by computing outer product X(:,i) * X(:,i)', then return upper triangular matrix using triu() and finally get nonzero elements of the result with nonzeros():
Y(:,i) = nonzeros( triu( X(:,i) * X(:,i)' ) );
I am still using for loop over columns. Is it possible to vectorize this nicely?
If you don't mind losing the triu part (that is, getting repeated values);
Y = reshape(bsxfun(#times, permute(X,[1 3 2]), permute(X,[3 1 2])), [],size(X,2))
To remove repeated rows of Y, corresponding to symmetric values of the X-row pairs (the equivalent of your nonzeros(triu)): precompute the pattern of rows to keep, and then use it to trim Y:
keep = nonzeros(triu(reshape(1:size(X,1)^2, size(X,1),size(X,1))));
Y = Y(keep,:);

Optimize parameters of a pairwise distance function in Matlab

This question is related to matlab: find the index of common values at the same entry from two arrays.
Suppose that I have an 1000 by 10000 matrix that contains value 0,1,and 2. Each row are treated as a sample. I want to calculate the pairwise distance between those samples according to the formula d = 1-1/(2p)sum(a/c+b/d) where a,b,c,d can treated as as the row vector of length 10000 according to some definition and p=10000. c and d are probabilities such that c+d=1.
An example of how to find the values of a,b,c,d: suppose we want to find d between sample i and bj, then I look at row i and j.
If kth entry of row i and j has value 2 and 2, then a=2,b=0,c=1,d=0 (I guess I will assign 0/0=0 in this case).
If kth entry of row i and j has value 2 and 1 or vice versa, then a=1,b=0,c=3/4,d=1/4.
The similar assignment will give to the case for 2,0(a=0,b=0,c=1/2,d=1/2),1,1(a=1,b=1,c=1/2,d=1/2),1,0(a=0,b=1,c=1/4,d=3/4),0,0(a=0,b=2,c=0,d=1).
The matlab code I have so far is using for loops for i and j, then find the cases above by using find, then create two arrays for a/c and b/d. This is extremely slow, is there a way that I can improve the efficiency?
Edit: the distance d is the formula given in this paper on page 13.
Provided those coefficients are fixed, then I think I've successfully vectorised the distance function. Figuring out the formulae was fun. I flipped things around a bit to minimise division, and since I wasn't aware of pdist until #horchler's comment, you get it wrapped in loops with the constants factored out:
% m is the data
[n p] = size(m, 1);
distance = zeros(n);
for ii=1:n
for jj=ii+1:n
a = min(m(ii,:), m(jj,:));
b = 2 - max(m(ii,:), m(jj,:));
c = 4 ./ (m(ii,:) + m(jj,:));
c(c == Inf) = 0;
d = 1 - c;
distance(ii,jj) = sum(a.*c + b.*d);
% distance(jj,ii) = distance(ii,jj); % optional for the full matrix
end
end
distance = 1 - (1 / (2 * p)) * distance;

Vector norm of an array of vectors in MATLAB

When calling norm on a matrix in MATLAB, it returns what's known as a "matrix norm" (a scalar value), instead of an array of vector norms. Is there any way to obtain the norm of each vector in a matrix without looping and taking advantage of MATLAB's vectorization?
You can compute the norm of each column or row of a matrix yourself by using element-wise arithmetic operators and functions defined to operate over given matrix dimensions (like SUM and MAX). Here's how you could compute some column-wise norms for a matrix M:
twoNorm = sqrt(sum(abs(M).^2,1)); %# The two-norm of each column
pNorm = sum(abs(M).^p,1).^(1/p); %# The p-norm of each column (define p first)
infNorm = max(M,[],1); %# The infinity norm (max value) of each column
These norms can easily be made to operate on the rows instead of the columns by changing the dimension arguments from ...,1 to ...,2.
From version 2017b onwards, you can use vecnorm.
The existing implementation for the two-norm can be improved.
twoNorm = sqrt(sum(abs(M).^2,1)); # The two-norm of each column
abs(M).^2 is going to be calculating a whole bunch of unnecessary square roots which just get squared straightaway.
Far better to do:
twoNorm = sqrt(
sum( real(M .* conj(M)), 1 )
)
This efficiently handles real and complex M.
Using real() ensures that sum and sqrt act over real numbers (rather than complex numbers with 0 imaginary component).
Slight addition to P i's answer:
norm_2 = #(A,dim)sqrt( sum( real(A).*conj(A) , dim) )
allows for
B=magic([2,3])
norm_2( B , 1)
norm_2( B , 2)
or as this if you want a norm_2.m file:
function norm_2__ = norm_2 (A_,dim_)
norm_2__ = sqrt( sum( real(A_).*conj(A_) , dim_) ) ;
end

Resources