Open
Description
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 ofmatrix_exp(tA) * B
.