[MATLAB] Making code faster/more efficient

  • Thread starter Thread starter BrownianMan
  • Start date Start date
  • Tags Tags
    Code Matlab
Click For Summary

Discussion Overview

The discussion focuses on optimizing MATLAB code for matrix exponentiation, specifically for a sparse matrix A and a vector B, where the operation A*B is performed repeatedly in a loop. Participants explore various strategies to enhance efficiency, including leveraging properties of exponents and binary decomposition of the exponent N.

Discussion Character

  • Technical explanation
  • Mathematical reasoning
  • Debate/contested

Main Points Raised

  • One participant identifies that the code's bottleneck is the repeated multiplication of a sparse matrix A with a vector B.
  • Another suggests precomputing A^N if A is constant, noting that even if A changes, special algorithms might improve efficiency.
  • A participant confirms that A is constant for each function call but varies with different inputs, complicating the use of precomputation.
  • There is a discussion about using properties of exponents to reduce the number of multiplications needed for A^N, with a proposal to compute powers of A incrementally.
  • One participant mentions writing a function to sum powers of 2 to represent N but finds this approach slower than expected.
  • Another participant emphasizes the importance of reusing previously computed powers of A to minimize calculations.
  • A detailed method is proposed for efficiently calculating A^N using binary representation of N, which involves squaring and multiplying selectively based on the bits of N.

Areas of Agreement / Disagreement

Participants generally agree on the potential benefits of optimizing matrix exponentiation through various methods, but there is no consensus on the most effective approach, as some methods proposed have yielded slower results.

Contextual Notes

Participants express uncertainty regarding the efficiency of their proposed methods, particularly in relation to the varying input size N and the computational cost associated with different strategies for exponentiation.

BrownianMan
Messages
133
Reaction score
0
A is a sparse matrix. B is a vector. I have the following code:

Code:
for j=1:N
    B=A*B;
end;

This part of the code is inside a function which gets called about 160000 times. I ran the Profiler and this part is the bottleneck. How can I make it more efficient?
 
Physics news on Phys.org
Does your A vary? If it is constant (or does not change every time), calculate A^n first.
Even it A is different every time, it might reduce the required time, as there could be special algorithms to calculate A^n more efficient.
 
Yes, A is constant.

I tried that. But the problem is that N is 200. So it actually takes more time to calculate A^N. I was wondering if there are more efficient ways to compute A^N. I tried using [v d]=eigs(A) and v*(d.^N)*v' but it said it wasn't able to find eigenvalues with sufficient accuracy.
 
BrownianMan said:
Yes, A is constant.

I tried that. But the problem is that N is 200. So it actually takes more time to calculate A^N. I was wondering if there are more efficient ways to compute A^N. I tried using [v d]=eigs(A) and v*(d.^N)*v' but it said it wasn't able to find eigenvalues with sufficient accuracy.

So A is only constant for each call of the function (it is different each time the function is called)?

Note that you can speed up exponentiation by taking advantage of some properties of exponents. Rather than repeatedly multiplying by A 200 times, there's nothing to prevent you forming A2 = A*A, then A4 = A2*A2, then A16 = A4*A4, and so on to carry out the bulk of the multiplications. Save appropriate intermediate results to have the right ones on hand: 200 = 128 + 64 + 8.
 
A depends on the inputs of the function, but inside the loop it does not change. For a given set of inputs, it is constant.

As far as taking advantage of properties of exponents, N is also an input. N=200 is what I am suppose to use to show that it gives the correct result for that specific N, but N can take on any integer value specified by the user. So I do not know N in advance.
 
BrownianMan said:
A depends on the inputs of the function, but inside the loop it does not change. For a given set of inputs, it is constant.

As far as taking advantage of properties of exponents, N is also an input. N=200 is what I am suppose to use to show that it gives the correct result for that specific N, but N can take on any integer value specified by the user. So I do not know N in advance.

Okay, but any N can be decomposed into a sum of powers of 2 in a similar fashion.
 
Is there a function that allows you to do that in Matlab?
 
BrownianMan said:
Is there a function that allows you to do that in Matlab?

Dunno. I'm not familiar with the Matlab function library. But it's the same as converting the decimal number N to binary. Each bit then represents a power of two.
 
gneill said:
Dunno. I'm not familiar with the Matlab function library. But it's the same as converting the decimal number N to binary. Each bit then represents a power of two.

Ok, I wrote a function to do that and then replaced the slow loop with this:

Code:
vec=sumPowersOf2(N); %vector of elements of powers of 2 that sum to N
AN=eye(N_space-1);
for i=1:numel(vec)
   AN=AN*A^vec(i);
end

But this is actually slower.
 
  • #10
The idea would be to reuse already computed powers, not compute each power of two individually. For example, if you've already computed A^2 and you need A^4, take the already computed value of A^2 and multiply it by itself...

For A^200 you'd be looking at 200 = 2^7 + 2^6 + 2^3, so

a2 = A*A
a4 = a2*a2
a8 = a4*a4
a16 = a8*a8
a32 = a16*a16
a64 = a32*a32
a128 = a64*a64

Then A^200 is given by a8*a64*a128

So a total of 9 matrix multiplies. Yes, there will be a tradeoff in terms of space -- keeping around a lot of partial results which might be large matrices will up the memory usage. You might be able to reuse the temporary variables which are not required for the final calculation. So in the above, the a2 variable is not required after a4 is calculated, and a4 is not required again after a8 is calculated, and so on. Just hang onto the ones you need at the end: a8, a64, a128.
 
  • #11
This should be quick:

N is stored as binary in your program anyway, for example as 11001000.
In addition, define two places to store matrices, which I call "power of A" and "result" here. Store A in "power of A" and 1 (the identity matrix) in "result".

Now, loop over the bits of N:
If the last bit is 1 (if 1 AND N is true, where AND is done bitwise), multiply "result" with "power of A". Otherwise, ignore that step.
Multiply "power of A" with "power of A".
Shift N by one bit (n=n/2, n>>1 or whatever MATLAB wants)
if N==0, quit, otherwise loop again

For N=200 as example, the results of the loop look like that:

N=11001000, "power of A"=A, "result"=1
(1 AND N)==0, do not change result, square "power of A", shift N...
N=1100100, "power of A"=A^2, "result"=1
... same as above
N=110010, "power of A"=A^4, "result"=1
N=11001, "power of A"=A^8, "result"=1
(1 AND N)==0, multiply "result" by "power of A", square "power of A", shift N...
N=1100, "power of A"=A^16, "result"=A^8
(1 AND N)==0, ...
N=110, "power of A"=A^32, "result"=A^8
N=11, "power of A"=A^64, "result"=A^8
N=1, "power of A"=A^128, "result"=A^72
N=0, "power of A"=A^256, "result"=A^200
Done. 10 non-trivial matrix multiplications required.

You can skip the last change of "power of A" with a bit more programming logic.
 

Similar threads

  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 2 ·
Replies
2
Views
2K
  • · Replies 13 ·
Replies
13
Views
3K
  • · Replies 10 ·
Replies
10
Views
2K
  • · Replies 1 ·
Replies
1
Views
2K
  • · Replies 6 ·
Replies
6
Views
3K
Replies
2
Views
2K
  • · Replies 3 ·
Replies
3
Views
2K
  • · Replies 7 ·
Replies
7
Views
2K