C++ RcppArmadillo expmat挂起4x4矩阵
我有一个病态的4x4矩阵,它使犰狳中的expmat函数挂起。病理基质为:C++ RcppArmadillo expmat挂起4x4矩阵,c++,r,matrix,rcpp,armadillo,C++,R,Matrix,Rcpp,Armadillo,我有一个病态的4x4矩阵,它使犰狳中的expmat函数挂起。病理基质为: a<-matrix(c(-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035 ,2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002 ,1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001 , 0e+000, 0
a<-matrix(c(-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035
,2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002
,1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001
, 0e+000, 0e+000, 0e+000, 0e+000), nrow=4, byrow=T)
我知道这个矩阵的条件很差,但R包expm中的expm函数可以使用默认算法毫无问题地处理它。在RcppArmadillo中有没有解决这个问题的方法?至少我想通过处理警告信息来避免绞刑
有一个类似的问题,但我不认为我的问题是一个复制品,因为我刚刚更新了Rcpp和RcppArmadillo在发布之前。另一个线程中的问题应该是由犰狳解决的,因此这里似乎还有其他问题。快速观察
几点注意:
中提供的expmat算法不同于arma::expmat算法
据推测,从链接后,这是固定在4.550.4。该更改似乎已经包括在内,因为文件源3与armadillo源相同,尽管RcppArmadillo似乎跳过了点版本,例如
在编写本文时提供的实际实现是,看起来无符号int已经被修复
调试arma::expmat命令
这句话,让我们用一些调试语句快速查看幕后的内容。注意:根据API文档,我选择T作为双精度
在短调试程序上:# include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
void run_exp_mat_routine(const arma::mat& x) {
const double norm_val = norm(x, "inf");
Rcpp::Rcout << "norm:" << norm_val << std::endl;
Rcpp::Rcout << "Value of T(0):" << (double(0)) << std::endl;
Rcpp::Rcout << "Inequality:" << (norm_val > double(0)) << std::endl;
Rcpp::Rcout << "log2: " << std::log2(norm_val) << std::endl;
int exponent = int(0); std::frexp(std::log2(norm_val), &exponent);
Rcpp::Rcout << "exponent: " << exponent << std::endl;
const arma::uword s = arma::uword( (std::max)(int(0), exponent + int(1)) );
Rcpp::Rcout << "s: " << s << std::endl;
const arma::mat AA = x / std::pow(2.0,s);
Rcpp::Rcout << "AA: " << std::endl << AA << std::endl;
double c = 0.5;
arma::mat E(AA.n_rows, AA.n_rows, arma::fill::eye);
Rcpp::Rcout << "Init E:" << std::endl << E << std::endl;
E += c * AA;
Rcpp::Rcout << "Mod E:" << std::endl << E << std::endl;
arma::mat D(AA.n_rows, AA.n_rows, arma::fill::eye);
Rcpp::Rcout << "Init D:" << std::endl << D << std::endl;
D -= c * AA;
Rcpp::Rcout << "Mod D:" << std::endl << D << std::endl;
arma::mat X = AA;
bool positive = true;
const arma::uword N = 6;
for(arma::uword i = 2; i<=N; ++i){
c = c * double(N - i + 1) / double(i * (2*N - i + 1));
X = AA * X;
E += c * X;
if(positive) { D += c * X; } else { D -= c * X; }
positive = (positive) ? false : true;
Rcpp::Rcout << "Loop: " << i << ", c: " << c << ", positive:" << positive << std::endl;
Rcpp::Rcout << "X: " << std::endl << X << std::endl << "E: " << std::endl << E << std::endl;
}
//arma::mat out = solve(D,E);
// Rcpp::Rcout << "out:" << std::endl << out << std::endl;
//
// for(arma::uword i = 0; i < s; ++i){
// out = out*out;
// }
// Rcpp::Rcout << "out: " << out <<std::endl;
}
/*** R
a <- matrix(c(-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035
,2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002
,1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001
, 0e+000, 0e+000, 0e+000, 0e+000), nrow=4, byrow=T)
run_exp_mat_routine(a)
*/
现在,循环部分似乎在最后一次迭代中触发了错误,例如i=6,因为数字太大,无法在双结构中表示
Loop: 2, c: 0.113636, positive:0
X:
2.5106e+115 1.8630e+53 -2.5106e+115 1.7447e+54
-2.8295e+55 5.1217e-03 2.8295e+55 2.1542e-05
-1.0428e+46 -2.6746e-06 1.0428e+46 -1.3347e-07
0 0 0 0
E:
2.8529e+114 2.1170e+52 -2.8529e+114 1.9826e+53
-3.2153e+54 9.6481e-01 3.2153e+54 1.2217e-05
-1.1850e+45 1.8287e-05 1.1850e+45 1.7409e-04
0 0 0 1.0000e+00
Loop: 3, c: 0.0151515, positive:1
X:
-1.2579e+173 -9.3347e+110 1.2579e+173 -8.7418e+111
1.4177e+113 1.0521e+51 -1.4177e+113 9.8524e+51
5.2251e+103 3.8774e+41 -5.2251e+103 3.6311e+42
0 0 0 0
E:
-1.9059e+171 -1.4143e+109 1.9059e+171 -1.3245e+110
2.1481e+111 1.5940e+49 -2.1481e+111 1.4928e+50
7.9168e+101 5.8748e+39 -7.9168e+101 5.5017e+40
0 0 0 1.0000e+00
Loop: 4, c: 0.00126263, positive:0
X:
6.3029e+230 4.6772e+168 -6.3029e+230 4.3801e+169
-7.1036e+170 -5.2714e+108 7.1036e+170 -4.9366e+109
-2.6181e+161 -1.9428e+99 2.6181e+161 -1.8194e+100
0 0 0 0
E:
7.9582e+227 5.9055e+165 -7.9582e+227 5.5305e+166
-8.9692e+167 -6.6557e+105 8.9692e+167 -6.2331e+106
-3.3056e+158 -2.4530e+96 3.3056e+158 -2.2972e+97
0 0 0 1.0000e+00
Loop: 5, c: 6.31313e-05, positive:1
X:
-3.1581e+288 -2.3435e+226 3.1581e+288 -2.1947e+227
3.5593e+228 2.6412e+166 -3.5593e+228 2.4735e+167
1.3118e+219 9.7344e+156 -1.3118e+219 9.1162e+157
0 0 0 0
E:
-1.9937e+284 -1.4795e+222 1.9937e+284 -1.3855e+223
2.2470e+224 1.6674e+162 -2.2470e+224 1.5616e+163
8.2815e+214 6.1454e+152 -8.2815e+214 5.7552e+153
0 0 0 1.0000e+00
Loop: 6, c: 1.50313e-06, positive:0
X:
inf 1.1742e+284 -inf 1.0997e+285
-1.7834e+286 -1.3234e+224 1.7834e+286 -1.2394e+225
-6.5728e+276 -4.8775e+214 6.5728e+276 -4.5677e+215
0 0 0 0
E:
inf 1.7650e+278 -inf 1.6529e+279
-2.6807e+280 -1.9892e+218 2.6807e+280 -1.8629e+219
-9.8797e+270 -7.3314e+208 9.8797e+270 -6.8658e+209
0 0 0 1.0000e+00
因此,无穷大符号被传递给solve参数,这将中断程序
除了运行一个单独的函数来检查矩阵是否为无穷大之外,我不确定还有其他方法,因为与其他方法相比,该算法似乎更合理。不过,我会让更有经验的人来评论这一点
编辑
使用expm::expma验证R中的输出
R中例程的快速示例:
# install.packages("expm")
library("expm")
a <- matrix(c(-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035
,2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002
,1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001
, 0e+000, 0e+000, 0e+000, 0e+000), nrow=4, byrow=T)
用MATLAB验证输出
由于这个函数应该提供类似的输出到MATLAB根据作者在链接后,让我们做快速运行
A = [-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035;
2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002;
1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001;
0e+000, 0e+000, 0e+000, 0e+000]
A在MATLAB中的表示形式为:
A=
为了获得不是按元素指数的指数矩阵,我们使用MATLAB的:
要旨
因此,R和MATLAB版本是一致的。因此,为armadillo中的矩阵分解选择的实现可能并不理想。更新rcpparmadillo并不等于更新armadillo,后者包含实际的算法。您使用的是哪一版本的armadillo?我如何检查armadillo的版本?我只能看到R中RcppArmadillo的版本是0.7.100.3.0。@MarcusMüller:这并不是说的那样,因为每个RcppArmadillo版本都倾向于隐藏相应的Armadillo版本——我们的0.7.100.3.*是基于Conrad的7.100.3。谢谢所有的细节。我们是否得出结论,这基本上是另一个“浮点数学”和有限精度问题?我认为这种情况下的错误肯定与浮点问题有关,因为获得了inf表示。然而,我认为它也基于犰狳中使用的指数矩阵算法,与MATLAB或R的等效算法相比,它的性能还差。感谢您进行了非常详细的调试。在算法进入无限循环之前,除了破解expmat的源代码之外,还有什么方法可以捕捉到这一点吗?在本例中,expmat抛出的警告不是运行时错误,因此我无法使用try catch截获它。或者我可以?或者只是使用expm from R.它导出函数;我在我的一个GitHub回购协议中使用它,而不是在CRAN上;还有针对它的单元测试。根据电子邮件线程,Armadillo的下一个版本提供了一个失败标志,该标志应指示“expmat”是否会由于其条件而失败
Loop: 2, c: 0.113636, positive:0
X:
2.5106e+115 1.8630e+53 -2.5106e+115 1.7447e+54
-2.8295e+55 5.1217e-03 2.8295e+55 2.1542e-05
-1.0428e+46 -2.6746e-06 1.0428e+46 -1.3347e-07
0 0 0 0
E:
2.8529e+114 2.1170e+52 -2.8529e+114 1.9826e+53
-3.2153e+54 9.6481e-01 3.2153e+54 1.2217e-05
-1.1850e+45 1.8287e-05 1.1850e+45 1.7409e-04
0 0 0 1.0000e+00
Loop: 3, c: 0.0151515, positive:1
X:
-1.2579e+173 -9.3347e+110 1.2579e+173 -8.7418e+111
1.4177e+113 1.0521e+51 -1.4177e+113 9.8524e+51
5.2251e+103 3.8774e+41 -5.2251e+103 3.6311e+42
0 0 0 0
E:
-1.9059e+171 -1.4143e+109 1.9059e+171 -1.3245e+110
2.1481e+111 1.5940e+49 -2.1481e+111 1.4928e+50
7.9168e+101 5.8748e+39 -7.9168e+101 5.5017e+40
0 0 0 1.0000e+00
Loop: 4, c: 0.00126263, positive:0
X:
6.3029e+230 4.6772e+168 -6.3029e+230 4.3801e+169
-7.1036e+170 -5.2714e+108 7.1036e+170 -4.9366e+109
-2.6181e+161 -1.9428e+99 2.6181e+161 -1.8194e+100
0 0 0 0
E:
7.9582e+227 5.9055e+165 -7.9582e+227 5.5305e+166
-8.9692e+167 -6.6557e+105 8.9692e+167 -6.2331e+106
-3.3056e+158 -2.4530e+96 3.3056e+158 -2.2972e+97
0 0 0 1.0000e+00
Loop: 5, c: 6.31313e-05, positive:1
X:
-3.1581e+288 -2.3435e+226 3.1581e+288 -2.1947e+227
3.5593e+228 2.6412e+166 -3.5593e+228 2.4735e+167
1.3118e+219 9.7344e+156 -1.3118e+219 9.1162e+157
0 0 0 0
E:
-1.9937e+284 -1.4795e+222 1.9937e+284 -1.3855e+223
2.2470e+224 1.6674e+162 -2.2470e+224 1.5616e+163
8.2815e+214 6.1454e+152 -8.2815e+214 5.7552e+153
0 0 0 1.0000e+00
Loop: 6, c: 1.50313e-06, positive:0
X:
inf 1.1742e+284 -inf 1.0997e+285
-1.7834e+286 -1.3234e+224 1.7834e+286 -1.2394e+225
-6.5728e+276 -4.8775e+214 6.5728e+276 -4.5677e+215
0 0 0 0
E:
inf 1.7650e+278 -inf 1.6529e+279
-2.6807e+280 -1.9892e+218 2.6807e+280 -1.8629e+219
-9.8797e+270 -7.3314e+208 9.8797e+270 -6.8658e+209
0 0 0 1.0000e+00
# install.packages("expm")
library("expm")
a <- matrix(c(-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035
,2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002
,1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001
, 0e+000, 0e+000, 0e+000, 0e+000), nrow=4, byrow=T)
[,1] [,2] [,3] [,4]
[1,] 2.403680e-62 0.02132743 1.369318 0.1998306
[2,] 1.543272e-60 1.36931834 41.028506 3.4698436
[3,] 2.403680e-62 0.02132743 1.369318 0.1998306
[4,] 0.000000e+00 0.00000000 0.000000 1.0000000
A = [-2.5654e+060,4.6979e-018,2.5654e+060,7.2765e-035;
2.8913e+000, -3.6633e+001,3.3731e+001,1.0003e-002;
1.0656e-009,1.9037e-002, -1.9732e-001,1.7828e-001;
0e+000, 0e+000, 0e+000, 0e+000]
1.0e+60 *
-2.5654 0.0000 2.5654 0.0000
0.0000 -0.0000 0.0000 0.0000
0.0000 0.0000 -0.0000 0.0000
0 0 0 0
ans =
0.0000 0.0213 1.3693 0.1998
0.0000 1.3693 41.0285 3.4698
0.0000 0.0213 1.3693 0.1998
0 0 0 1.0000