What's a floating-point operation and how to count them (in MATLAB)? - matlab

I have an assignment where I basically need to count the number of floating point operations in a simple program, which involves a loop, a matrix, and operations such as *, + and ^.
From my understanding, a floating-point operation is an operation that involves floating-point numbers, and we may be interested in counting these operations because I think they may be more expensive for the computer. If you want to add more details to this part, it would be nice.
My problem is that I've no idea of knowing exactly which operations involve floating-point numbers, unless I use functions, such as isfloat. In that case, would just one of the numbers in the operation be necessary to be floating-point to the operation be considered a floating-point operation, right? If not, why? Can you add more details on this?
For example, suppose I've the following simple function:
function [r, n] = naive(c, x)
% c is the vector of coefficients of the polynomial
% The coeffiecients should be given as follows
% c(1) = coefficient of x^0 (or 1).
% c(length(c)) = coefficient of the largest power of x
% x is the point to evaluate the polynomial at
% r is the result of the evaluation
% (Assumes that the entries are integers)
r = c(1);
n = 0;
for i=2:length(c)
r = r + c(i) * x^(i - 1);
n = n + 2 + (i - 1);
end
end
which basically calculates a normal polynomial evaluated at x given the coefficients in a vector c.
As you can see from the code, n is actually keeping track of floating-point operations. But actually, I'm counting every mathematical operation (except the assignment) as a floating-point operation, but this of course might not be right, or is it? If yes or no, why?
Both the coefficients and c might be floating-point numbers. So, instead of counting every operation as a floating point operation, should we first check with for example isfloat if the numbers are floating point, and only then increment n?
Note, I'm aware of the function flops, which, from what I understood, it should count the floating-point operations, but it's deprecated, and mostly I would like to learn better these concepts, and therefore try to count them manually.
Thanks for any help!

Related

slow calculation of General Polynomial Equation

I'm trying to make a General Polynomial Function which given the time period to calculate it, the highest Polynomial power powr, and each constant a; which a and powr are the same length.
My approach of the code is the following: where each element of time is transformed into a vector from powr then when multiplied element by element with a, then calculating the sum of the resulting vector to make it one element.
for i=1:length(time)
result(i)=sum((time(i).^[powr]).*[a]);
end
Problem is that It takes way too long to do this calculation the more elements time has and/or the longer a and powr are. Is there a way to do this calculation faster ?
Armia:
The reason the code runs slowly is that the computation is not polynomially factored, meaning that it doesn't take advantage of the running products. Say for example your polynomial is of degree 3 (i.e., y = a*x^3 + b*x^2 + c*x + d). The way your code is set up makes it so that x (analogous to your time variable) would first be cubed (3 multiplications + 1 to multiply by a), then squared (2 multiplications + 1 to multiply by b), then referenced (0 multiplications + 1 to multiply by c), and finally, you add d. This amounts to 9 multiplications and 3 additions. Evaluating polynomials this way requires sum(1:n) multiplications and n additions.
If instead one factors the polynomial as: y = ((a*x + b)*x + c)*x + d the number of multiplications goes down to 3 (from 9) and the additions remain at 3. In fact, the polynomial factoring approach evaluates the polynomial with n multiplications and n additions (n is the order of the polynomial). Thus, one can see that polynomial factoring scales in computational effort significantly slower than, let's call it, the brute force approach.
To do this for higher degree polynomials, I suggest you modify the code to:
N = length(time); %Get number of time values on which the polynomial evaluation is needed.
hmp = length(a); %I'm assuming a contains the polynomial coefficients in ascending order.
result = ones(N,1)*a(end); %Preallocate memory for results.
for i=hmp-1:-1:1
result = result.*time + a(i); %Compute the factored parenthesis 'outward'
end
Where N is the number of time values at which you want to evaluate the polynomial, hmp is the highest magnitude power. Making result a vector makes the loop compute the polynomial for all your time entries simultaneously. This for loop takes advantage of polynomial factoring, which will scale much more lovely than unnecessarily having to compute powers from scratch element by element.

Why does treating the index as a continuous variable not work when performing an inverse discrete Fourier transform?

I have a set of points describing a closed curve in the complex plane, call it Z = [z_1, ..., z_N]. I'd like to interpolate this curve, and since it's periodic, trigonometric interpolation seemed a natural choice (especially because of its increased accuracy). By performing the FFT, we obtain the Fourier coefficients:
F = fft(Z);
At this point, we could get Z back by the formula (where 1i is the imaginary unit, and we use (k-1)*(n-1) because MATLAB indexing starts at 1)
N
Z(n) = (1/N) sum F(k)*exp( 1i*2*pi*(k-1)*(n-1)/N), 1 <= n <= N.
k=1
My question
Is there any reason why n must be an integer? Presumably, if we treat n as any real number between 1 and N, we will just get more points on the interpolated curve. Is this true? For example, if we wanted to double the number of points, could we not set
N
Z_new(n) = (1/N) sum F(k)*exp( 1i*2*pi*(k-1)*(n-1)/N), with n = 1, 1.5, 2, 2.5, ..., N-1, N-0.5, N
k=1
?
The new points are of course just subject to some interpolation error, but they'll be fairly accurate, right? The reason I'm asking this question is because this method is not working for me. When I try to do this, I get a garbled mess of points that makes no sense.
(By the way, I know that I could use the interpft() command, but I'd like to add points only in certain areas of the curve, for example between z_a and z_b)
The point is when n is integer, you have some primary functions which are orthogonal and can be as a basis for the space. When, n is not integer, The exponential functions in the formula, are not orthogonal. Hence, the expression of a function based on these non-orthogonal basis is not meaningful as much as you expected.
For orthogonality case you can see the following as an example (from here). As you can check, you can find two n_1 and n_2 which are not integer, the following integrals are not zero any more, and they are not orthogonal.

How to calculate matrix entries efficently using Matlab

I have a cell array myBasis of sparse matricies B_1,...,B_n.
I want to evaluate with Matlab the matrix Q(i,j) = trace (B^T_i * B_j).
Therefore, I wrote the following code:
for i=1:n
for j=1:n
B=myBasis{i};
C=myBasis{j};
Q(i,j)=trace(B'*C);
end
end
Which takes already 68 seconds when n=1226 and B_i has 50 rows, and 50 colums.
Is there any chance to speed this up? Usually I exclude for-loops from my matlab code in a c++ file - but I have no experience how to handle a sparse cell array in C++.
As noted by Inox Q is symmetric and therefore you only need to explicitly compute half the entries.
Computing trace( B.'*C ) is equivalent to B(:).'*C(:):
trace(B.'*C) = sum_i [B.'*C]_ii = sum_i sum_j B_ij * C_ij
which is the sum of element-wise products and therefore equivalent to B(:).'*C(:).
When explicitly computing trace( B.'*C ) you are actually pre-computing all k-by-k entries of B.'*C only to use the diagonal later on. AFAIK, Matlab does not optimize its calculation to save it from computing all the entries.
Here's a way
for ii = 1:n
B = myBasis{ii};
for jj = ii:n
C = myBasis{jj};
t = full( B(:).'*C(:) ); % equivalent to trace(B'*C)!
Q(ii,jj) = t;
Q(jj,ii) = t;
end
end
PS,
It is best not to use i and j as variable names in Matlab.
PPS,
You should notice that ' operator in Matlab is not matrix transpose, but hermitian conjugate, for actual transpose you need to use .'. In most cases complex numbers are not involved and there is no difference between the two operators, but once complex data is introduced, confusing between the two operators makes debugging quite a mess...
Well, a couple of thoughts
1) Basic stuff: A'*B = (B'*A)' and trace(A) = trace(A'). Well, only this trick cut your calculations by almost 50%. Your Q(i,j) matrix is symmetric, and you only need to calculate n(n+1)/2 terms (and not n²)
2) To calculate the trace you don't need to calculate every term of B'*C, just the diagonal. Nevertheless, I don't know if it's easy to create a script in Matlab that is actually faster then just calculating B'*C (MatLab is pretty fast with matrix operations).
But I would definitely implement (1)

how to raise the fourier transformed probability density function to a fractional power?

By hypothesis my measured probability density functions (PDF) result from n convolutions of an elementary distribution (E).
I have two distributions the first (F) of which is supposed to have undergone more convolutions (m_1) than the second (G) (m_2 convolutions).
In fourier space:
F' = E'^m_1
G' = E'^m_2
As the two PDFs are constituted from the same elementary distribution, I should be able to be able to calculate the PDF of G from F
G' = F'^{m_1/m_2}
Taking the IFFT i should have a distribution that overlaps well with G.
A naive way of doing this would to be simply to calculate the FT of F and raise it to the power 1/integer and testing a range of integers.
My question are there any tricks for raising the Fourier transformed PDF to a fractional power. I have done so but the IFFT gives a distribution far from that which is expected. And strange aliasing errors.
I've included a padded vector as one might do if they were to do a convolution of two PDFS.
My normalization is based on the fact that the k=0 [ProbF(1,1)] wave vector gives the integral of the PDF which should be equal to one.
Of course, the hypothesis could be wrong, but it has all the reasons in the world to be valid.
My code
Inc = INC1 ; % BINS
null = zeros(1,length(Inc)); % PADDED PROB
Inc = [ Inc.*-1 (Inc) ]; % PADDED INC VECTOR
Prob = [ null heightProb1 ] ; % PADDED PROB VECTOR
ProbF = (fft(Prob)) ;
ProbFnorm = ProbF./ProbF(1,1) ; % NORMALIZED BY K=0 COMPONENT (integral of PDF =1)
m=.79 % POWER TO RAISE
ProbFtrans = ((ProbFnorm).^(m)); % 'DECONVOLUTION' IN FOURIER SPACE
ProbIF = (ifft((ProbFtrans)).*(ProbF(1,1))); % RETURN TO PROBABILITY SPACE
figure(2);
plot(Inc,ProbIF,'rs')
Thank you in advance for your help
Fourier coefficients are typically complex numbers (unless your function is symmetric).
You should be very careful when you raise complex numbers to fractional powers.
For example, consider
z=1.2 + i*0.65;
then raise z to power 4
>> z^4
ans =
-1.398293750000001e+00 + 3.174599999999999e+00i
and to power 8.
>> z^8
ans =
-8.122859748710933e+00 - 8.878046677500002e+00i
Then try obtain z^4 as (z^8)^(1/2)
>> (z^8)^(1/2)
ans =
1.398293750000001e+00 - 3.174600000000000e+00i
Surprise! You don't get z^4! (wrong sign)
If you avoid taking the fractional power and "rewind" z^8 by diving back by z you get back z^4 correctly:
>> (z^8)/z/z/z/z
ans =
-1.398293750000000e+00 + 3.174599999999998e+00i
The reason is in the definition of fractional powers in the complex plane. Fractional powers are multi-valued functions, which are made single-valued by introducing a branch-cut in the complex plane. The nth-root z^(1/n) has n possible values, and
matlab singles out one of these by interpreting the complex function z^(1/n) as its so-called principal branch. The main implication is that in the world of complex numbers ^1/n does not always invert ^n.
If this doesn't make any sense to you, you should probably review some basic complex analysis, but the bottom line is that fractional powers of complex numbers are tricky animals. Wherever possible you should try to work around fractional powers by using division (as show above).
I am not sure this will fix all of your problems, but from your description it looks like this is certainly one problem you have.

Faster projected-norm (quadratic-form, metric-matrix...) style computations

I need to perform lots of evaluations of the form
X(:,i)' * A * X(:,i) i = 1...n
where X(:,i) is a vector and A is a symmetric matrix. Ostensibly, I can either do this in a loop
for i=1:n
z(i) = X(:,i)' * A * X(:,i)
end
which is slow, or vectorise it as
z = diag(X' * A * X)
which wastes RAM unacceptably when X has a lot of columns. Currently I am compromising on
Y = A * X
for i=1:n
z(i) = Y(:,i)' * X(:,i)
end
which is a little faster/lighter but still seems unsatisfactory.
I was hoping there might be some matlab/scilab idiom or trick to achieve this result more efficiently?
Try this in MATLAB:
z = sum(X.*(A*X));
This gives results equivalent to Federico's suggestion using the function DOT, but should run slightly faster. This is because the DOT function internally computes the result the same way as I did above using the SUM function. However, DOT also has additional input argument checks and extra computation for cases where you are dealing with complex numbers, which is extra overhead you probably don't want or need.
A note on computational efficiency:
Even though the time difference is small between how fast the two methods run, if you are going to be performing the operation many times over it's going to start to add up. To test the relative speeds, I created two 100-by-100 matrices of random values and timed the two methods over many runs to get an average execution time:
METHOD AVERAGE EXECUTION TIME
--------------------------------------------
Z = sum(X.*Y); 0.0002595 sec
Z = dot(X,Y); 0.0003627 sec
Using SUM instead of DOT therefore reduces the execution time of this operation by about 28% for matrices with around 10,000 elements. The larger the matrices, the more negligible this difference will be between the two methods.
To summarize, if this computation represents a significant bottleneck in how fast your code is running, I'd go with the solution using SUM. Otherwise, either solution should be fine.
Try this:
z = dot(X, A*X)
I don't have Matlab here to test, but it works on Octave, so I expect Matlab to have an analogous dot() function.
From Octave's help:
-- Function File: dot (X, Y, DIM)
Computes the dot product of two vectors. If X and Y are matrices,
calculate the dot-product along the first non-singleton dimension.
If the optional argument DIM is given, calculate the dot-product
along this dimension.
For completeness, gnovice's answer in Scilab would be
z = sum(X .* Y, 1)'