Search code examples
matlabmatrix-multiplicationpolynomials

Compute weighted summation of matrix power (matrix polynomial) in Matlab


Given an nxn matrix A_k and a nx1 vector x, is there any smart way to compute

enter image description here

using Matlab? x_i are the elements of the vector x, therefore J is a sum of matrices. So far I have used a for loop, but I was wondering if there was a smarter way.


Solution

  • Short answer: you can use the builtin matlab function polyvalm for matrix polynomial evaluation as follows:

    x = x(end:-1:1); % flip the order of the elements
    x(end+1) = 0; % append 0
    J = polyvalm(x, A);
    

    Long answer: Matlab uses a loop internally. So, you didn't gain that much or you perform even worse if you optimise your own implementation (see my calcJ_loopOptimised function):

    % construct random input
    n = 100;
    A = rand(n);
    x = rand(n, 1);
    
    % calculate the result using different methods
    Jbuiltin = calcJ_builtin(A, x);
    Jloop = calcJ_loop(A, x);
    JloopOptimised = calcJ_loopOptimised(A, x);
    
    % check if the functions are mathematically equivalent (should be in the order of `eps`)
    relativeError1 = max(max(abs(Jbuiltin - Jloop)))/max(max(Jbuiltin))
    relativeError2 = max(max(abs(Jloop - JloopOptimised)))/max(max(Jloop))
    
    % measure the execution time
    t_loopOptimised = timeit(@() calcJ_loopOptimised(A, x))
    t_builtin = timeit(@() calcJ_builtin(A, x))
    t_loop = timeit(@() calcJ_loop(A, x))
    
    % check if builtin function is faster
    builtinFaster = t_builtin < t_loopOptimised
    
    % calculate J using Matlab builtin function
    function J = calcJ_builtin(A, x)
      x = x(end:-1:1);
      x(end+1) = 0;
      J = polyvalm(x, A);
    end
    
    % naive loop implementation
    function J = calcJ_loop(A, x)
      n = size(A, 1);
      J = zeros(n,n);
      for i=1:n
        J = J + A^i * x(i);
      end
    end
    
    % optimised loop implementation (cache result of matrix power)
    function J = calcJ_loopOptimised(A, x)
      n = size(A, 1);
      J = zeros(n,n);
      A_ = eye(n);
      for i=1:n
        A_ = A_*A;
        J = J + A_ * x(i);
      end
    end
    

    For n=100, I get the following:

    t_loopOptimised = 0.0077
    t_builtin       = 0.0084
    t_loop          = 0.0295
    

    For n=5, I get the following:

    t_loopOptimised = 7.4425e-06
    t_builtin       = 4.7399e-05
    t_loop          = 1.0496e-04 
    

    Note that my timings fluctuates somewhat between different runs, but the optimised loop is almost always faster (up to 6x for small n) than the builtin function.