Skip to content

precision of scale_matrix_exp_multiply #1146

Open
@lukas-rokka

Description

@lukas-rokka

Description

scale_matrix_exp_multiply(t, A, B) doesn't always equal matrix_exp(tA) * B. Might be a precision issue, where scale_matrix_exp_multiply does some sort of approximation and therefore doesn't give same result as matrix_exp(tA) * B when A has a low condition number.

Example

This example is based on the discretization of Linear Time-Invariant ODE systems (https://github.com/eddelbuettel/rcppkalman/blob/master/src/ltidisc.cpp).

Ac =t(matrix(c(-4.47584,0.0732692,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0.0183173,-0.0366346,0.0183173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0.0146538,-0.179407,0,0,0.0268619,0,0.00639568,0,0.0639568,0,0,0.0426379,0.0249012,0.00748033,0.00498689,0.00415574,
0,0,0,-5.86896,0.447212,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0.223606,-0.447212,0.223606,0,0,0,0,0,0,0,0,0,0,0,
0,0,0.328758,0,0.447212,-2.33289,0,0.0493138,0,0.493138,0,0,0.328758,0.685714,0.0576769,0.0384513,0.0320427,
0,0,0,0,0,0,-42.15,11.4398,0,0,0,0,0,0,0,0,0,
0,0,2.3972,0,0,1.51023,11.4398,-26.3403,0,3.59579,0,0,2.3972,5,0.420561,0.280374,0.233645,
0,0,0,0,0,0,0,0,-0.122394,0.122394,0,0,0,0,0,0,0,
0,0,1.09586,0,0,0.690393,0,0.164379,1.10155,-6.43376,0,0,1.09586,2.28571,0.192256,0.128171,0.106809,
0,0,0,0,0,0,0,0,0,0,-0.00471794,0.0014969,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0.0190116,-0.0402984,0.0212869,0,0,0,0,
0,0,0.0426379,0,0,0.0268619,0,0.00639568,0,0.0639568,0,0.0170295,-0.334747,0.177866,0.00748033,0.00498689,0.00415574,
0,0,0.269588,0,0,0.606573,0,0.144422,0,1.44422,0,0,1.92563,-4.39043,0.0385126,0.15405,0.192563,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1), 17))

stan_code <- "
functions  {
  // Discretize Linear Time-Invariant ODE with Gaussian Noise
  matrix lti_disc(int m, matrix Ac, matrix Qc, real dt) {
    int m1 = m+1;
    int m2 = m*2;
    matrix[m2, m2] phi;
    matrix[m2, m] OI;
    matrix[m2, m] AB;
    matrix[m2, m] AB2;
    matrix[m, m] Q;
    
    OI[1:m, 1:m] = rep_matrix(0., m, m);
    OI[m1:m2, 1:m] = diag_matrix(rep_vector(1., m));
    
    phi[1:m, 1:m] = Ac;
    phi[1:m, m1:m2] = Qc;
    phi[m1:m2, 1:m] = rep_matrix(0., m, m);
    phi[m1:m2, m1:m2] = -Ac';
    
    AB = matrix_exp(phi*dt) * OI;
    AB2 = scale_matrix_exp_multiply(dt, phi, OI);
    
    // return the difference between the two methods. 
    return AB - AB2;
    
    // The actual return code 
    //Q = AB[1:m, ] / AB[m1:m2, ];
    //return Q;
  }
}
parameters {}
model {}"

expose_stan_functions(stanc(model_code = stan_code))

# should be close to zero
sum(lti_disc(17, Ac, Qc=diag(c(rep(0.1, 17))), dt=0.1))  # is close to zero
sum(lti_disc(17, Ac, Qc=diag(c(rep(0.1, 17))), dt=1))  # far from zero

Setting the dt = 0.1 when calling the ´lti_disc´ function returns an expected result. Somewhere at dt > 0.15 the scale_matrix_exp_multiply fails to return similar result as matrix_exp(tA) * B.

For feature requests:

  • if possible, let the user set the precision of scale_matrix_exp_multiply
  • make it clear in the documentation that scale_matrix_exp_multiply(t, A, B) is an approximation of matrix_exp(tA) * B.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions