forked from opencollab/arpack-ng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
detect_arpack_bug.m4
158 lines (133 loc) · 4.56 KB
/
detect_arpack_bug.m4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
dnl
dnl Check whether ARPACK works (does not crash)
dnl
dnl Using a pure Fortran program doesn't seem to crash when linked
dnl with the buggy ARPACK library but the C++ program does. Maybe
dnl it is the memory allocation that exposes the bug and using statically
dnl allocated arrays in Fortran does not?
dnl
dnl This code is not used by arpack-ng itself.
dnl This is a macro for applications using arpack to detect that the version
dnl of arpack behave correctly (ie not arpack-ng)
dnl This is the work of Rik <[email protected]>
dnl
dnl This code is released under the same license as arpack
dnl
AC_DEFUN([CHECK_ARPACK_OK], [
AC_LANG_PUSH(C++)
AC_CACHE_CHECK([whether the arpack library works],
[cv_lib_arpack_ok], [
AC_RUN_IFELSE([AC_LANG_PROGRAM([[
// External functions from ARPACK library
extern "C" int
F77_FUNC (dnaupd, DNAUPD) (int&, const char *, const int&, const char *,
int&, const double&, double*, const int&,
double*, const int&, int*, int*, double*,
double*, const int&, int&, long int, long int);
extern "C" int
F77_FUNC (dneupd, DNEUPD) (const int&, const char *, int*, double*,
double*, double*, const int&,
const double&, const double&, double*,
const char*, const int&, const char *,
int&, const double&, double*, const int&,
double*, const int&, int*, int*, double*,
double*, const int&, int&, long int,
long int, long int);
extern "C" int
F77_FUNC (dgemv, DGEMV) (const char *, const int&, const int&,
const double&, const double*, const int&,
const double*, const int&, const double&,
double*, const int&, long int);
#include <cfloat>
void
doit (void)
{
// Based on the octave function EigsRealNonSymmetricMatrix from
// liboctave/eigs-base.cc.
// Problem matrix. See bug #31479
int n = 4;
double *m = new double [n * n];
m[0] = 1, m[4] = 0, m[8] = 0, m[12] = -1;
m[1] = 0, m[5] = 1, m[9] = 0, m[13] = 0;
m[2] = 0, m[6] = 0, m[10] = 1, m[14] = 0;
m[3] = 0, m[7] = 0, m[11] = 2, m[15] = 1;
double *resid = new double [4];
resid[0] = 0.960966;
resid[1] = 0.741195;
resid[2] = 0.150143;
resid[3] = 0.868067;
int *ip = new int [11];
ip[0] = 1; // ishift
ip[1] = 0; // ip[1] not referenced
ip[2] = 300; // mxiter, maximum number of iterations
ip[3] = 1; // NB blocksize in recurrence
ip[4] = 0; // nconv, number of Ritz values that satisfy convergence
ip[5] = 0; // ip[5] not referenced
ip[6] = 1; // mode
ip[7] = 0; // ip[7] to ip[10] are return values
ip[8] = 0;
ip[9] = 0;
ip[10] = 0;
int *ipntr = new int [14];
int k = 1;
int p = 3;
int lwork = 3 * p * (p + 2);
double *v = new double [n * (p + 1)];
double *workl = new double [lwork + 1];
double *workd = new double [3 * n + 1];
int ido = 0;
int info = 0;
double tol = DBL_EPSILON;
do
{
F77_FUNC (dnaupd, DNAUPD) (ido, "I", n, "LM", k, tol, resid, p,
v, n, ip, ipntr, workd, workl, lwork,
info, 1L, 2L);
if (ido == -1 || ido == 1 || ido == 2)
{
double *x = workd + ipntr[0] - 1;
double *y = workd + ipntr[1] - 1;
F77_FUNC (dgemv, DGEMV) ("N", n, n, 1.0, m, n, x, 1, 0.0,
y, 1, 1L);
}
else
{
if (info < 0)
{
return; // Error
}
break;
}
}
while (1);
int *sel = new int [p];
// In Octave, the dimensions of dr and di are k+1, but k+2 avoids segfault
double *dr = new double [k + 1];
double *di = new double [k + 1];
double *workev = new double [3 * p];
for (int i = 0; i < k + 1; i++)
dr[i] = di[i] = 0.;
int rvec = 1;
double sigmar = 0.0;
double sigmai = 0.0;
// In Octave, this is n*(k+1), but k+2 avoids segfault
double *z = new double [n * (k + 1)];
F77_FUNC (dneupd, DNEUPD) (rvec, "A", sel, dr, di, z, n, sigmar,
sigmai, workev, "I", n, "LM", k, tol,
resid, p, v, n, ip, ipntr, workd,
workl, lwork, info, 1L, 1L, 2L);
}
]], [[
for (int i = 0; i < 10; i++)
doit ();
]])],
[cv_lib_arpack_ok=yes],
[cv_lib_arpack_ok=no],
[cv_lib_arpack_ok=yes])])
AC_LANG_POP(C++)
if test "$cv_lib_arpack_ok" = "yes"; then
$1
else
$2
fi
])