1
/* Modified: Piotr Held <pjheld@gmail.com> (2015).
2
* These functions are based on eigen.c of TISEAN 3.0.1 https://github.com/heggus/Tisean"
4
/********************************************************************/
5
/********************************************************************/
7
#include <octave/oct.h>
13
typedef double doublereal;
16
#define abs(x) (((x)>=0.0)?(x):-(x))
17
#define min(x,y) (((x)<=(y))?(x):(y))
18
#define max(x,y) (((x)>=(y))?(x):(y))
20
static doublereal c_b10 = 1.;
22
extern void check_alloc(void*);
24
double d_sign(double *a,double *b)
27
x = (*a >= 0 ? *a : - *a);
28
return ( *b >= 0 ? x : -x);
31
doublereal pythag(doublereal *a, doublereal *b)
33
doublereal ret_val, d__1, d__2, d__3;
34
static doublereal p, r__, s, t, u;
36
d__1 = abs(*a), d__2 = abs(*b);
41
d__2 = abs(*a), d__3 = abs(*b);
42
d__1 = min(d__2,d__3) / p;
53
r__ = d__1 * d__1 * r__;
61
int tred2(const integer *nm, const integer *n, doublereal *a,
62
doublereal *d__, doublereal *e, doublereal *z__)
64
integer a_dim1, a_offset, z_dim1, z_offset, i__1, i__2, i__3;
67
double sqrt(doublereal), d_sign(doublereal *, doublereal *);
69
static doublereal f, g, h__;
70
static integer i__, j, k, l;
72
static integer ii, jp1;
73
static doublereal scale;
77
/* this subroutine is a translation of the algol procedure tred2, */
78
/* num. math. 11, 181-195(1968) by martin, reinsch, and wilkinson. */
79
/* handbook for auto. comp., vol.ii-linear algebra, 212-226(1971). */
81
/* this subroutine reduces a real symmetric matrix to a */
82
/* symmetric tridiagonal matrix using and accumulating */
83
/* orthogonal similarity transformations. */
87
/* nm must be set to the row dimension of two-dimensional */
88
/* array parameters as declared in the calling program */
89
/* dimension statement. */
91
/* n is the order of the matrix. */
93
/* a contains the real symmetric input matrix. only the */
94
/* lower triangle of the matrix need be supplied. */
98
/* d contains the diagonal elements of the tridiagonal matrix. */
100
/* e contains the subdiagonal elements of the tridiagonal */
101
/* matrix in its last n-1 positions. e(1) is set to zero. */
103
/* z contains the orthogonal transformation matrix */
104
/* produced in the reduction. */
106
/* a and z may coincide. if distinct, a is unaltered. */
108
/* questions and comments should be directed to burton s. garbow, */
109
/* mathematics and computer science div, argonne national laboratory */
111
/* this version dated august 1983. */
113
/* ------------------------------------------------------------------ */
116
z_offset = 1 + z_dim1 * 1;
121
a_offset = 1 + a_dim1 * 1;
125
for (i__ = 1; i__ <= i__1; ++i__) {
128
for (j = i__; j <= i__2; ++j) {
129
z__[j + i__ * z_dim1] = a[j + i__ * a_dim1];
132
d__[i__] = a[*n + i__ * a_dim1];
139
for (ii = 2; ii <= i__1; ++ii) {
148
for (k = 1; k <= i__2; ++k) {
149
scale += (d__1 = d__[k], abs(d__1));
159
for (j = 1; j <= i__2; ++j) {
160
d__[j] = z__[l + j * z_dim1];
161
z__[i__ + j * z_dim1] = 0.;
162
z__[j + i__ * z_dim1] = 0.;
169
for (k = 1; k <= i__2; ++k) {
171
h__ += d__[k] * d__[k];
176
g = -d_sign(&d__1, &f);
181
for (j = 1; j <= i__2; ++j) {
186
for (j = 1; j <= i__2; ++j) {
188
z__[j + i__ * z_dim1] = f;
189
g = e[j] + z__[j + j * z_dim1] * f;
196
for (k = jp1; k <= i__3; ++k) {
197
g += z__[k + j * z_dim1] * d__[k];
198
e[k] += z__[k + j * z_dim1] * f;
207
for (j = 1; j <= i__2; ++j) {
212
hh = f / (h__ + h__);
214
for (j = 1; j <= i__2; ++j) {
218
for (j = 1; j <= i__2; ++j) {
223
for (k = j; k <= i__3; ++k) {
224
z__[k + j * z_dim1] = z__[k + j * z_dim1] - f * e[k] - g *
228
d__[j] = z__[l + j * z_dim1];
229
z__[i__ + j * z_dim1] = 0.;
236
for (i__ = 2; i__ <= i__1; ++i__) {
238
z__[*n + l * z_dim1] = z__[l + l * z_dim1];
239
z__[l + l * z_dim1] = 1.;
246
for (k = 1; k <= i__2; ++k) {
247
d__[k] = z__[k + i__ * z_dim1] / h__;
251
for (j = 1; j <= i__2; ++j) {
255
for (k = 1; k <= i__3; ++k) {
256
g += z__[k + i__ * z_dim1] * z__[k + j * z_dim1];
260
for (k = 1; k <= i__3; ++k) {
261
z__[k + j * z_dim1] -= g * d__[k];
267
for (k = 1; k <= i__3; ++k) {
268
z__[k + i__ * z_dim1] = 0.;
275
for (i__ = 1; i__ <= i__1; ++i__) {
276
d__[i__] = z__[*n + i__ * z_dim1];
277
z__[*n + i__ * z_dim1] = 0.;
280
z__[*n + *n * z_dim1] = 1.;
285
int tql2(const integer *nm, const integer *n, doublereal *d__,
286
doublereal *e, doublereal *z__, integer *ierr)
288
integer z_dim1, z_offset, i__1, i__2, i__3;
289
doublereal d__1, d__2;
291
double d_sign(doublereal *, doublereal *);
293
static doublereal c__, f, g, h__;
294
static integer i__, j, k, l, m;
295
static doublereal p, r__, s, c2, c3;
296
static integer l1, l2;
297
static doublereal s2;
299
static doublereal dl1, el1;
301
static doublereal tst1, tst2;
302
extern doublereal pythag_(doublereal *, doublereal *);
306
/* this subroutine is a translation of the algol procedure tql2, */
307
/* num. math. 11, 293-306(1968) by bowdler, martin, reinsch, and */
309
/* handbook for auto. comp., vol.ii-linear algebra, 227-240(1971). */
311
/* this subroutine finds the eigenvalues and eigenvectors */
312
/* of a symmetric tridiagonal matrix by the ql method. */
313
/* the eigenvectors of a full symmetric matrix can also */
314
/* be found if tred2 has been used to reduce this */
315
/* full matrix to tridiagonal form. */
319
/* nm must be set to the row dimension of two-dimensional */
320
/* array parameters as declared in the calling program */
321
/* dimension statement. */
323
/* n is the order of the matrix. */
325
/* d contains the diagonal elements of the input matrix. */
327
/* e contains the subdiagonal elements of the input matrix */
328
/* in its last n-1 positions. e(1) is arbitrary. */
330
/* z contains the transformation matrix produced in the */
331
/* reduction by tred2, if performed. if the eigenvectors */
332
/* of the tridiagonal matrix are desired, z must contain */
333
/* the identity matrix. */
337
/* d contains the eigenvalues in ascending order. if an */
338
/* error exit is made, the eigenvalues are correct but */
339
/* unordered for indices 1,2,...,ierr-1. */
341
/* e has been destroyed. */
343
/* z contains orthonormal eigenvectors of the symmetric */
344
/* tridiagonal (or full) matrix. if an error exit is made, */
345
/* z contains the eigenvectors associated with the stored */
349
/* zero for normal return, */
350
/* j if the j-th eigenvalue has not been */
351
/* determined after 30 iterations. */
353
/* calls pythag for dsqrt(a*a + b*b) . */
355
/* questions and comments should be directed to burton s. garbow, */
356
/* mathematics and computer science div, argonne national laboratory */
358
/* this version dated august 1983. */
360
/* ------------------------------------------------------------------ */
363
z_offset = 1 + z_dim1 * 1;
374
for (i__ = 2; i__ <= i__1; ++i__) {
383
for (l = 1; l <= i__1; ++l) {
385
h__ = (d__1 = d__[l], abs(d__1)) + (d__2 = e[l], abs(d__2));
390
for (m = l; m <= i__2; ++m) {
391
tst2 = tst1 + (d__1 = e[m], abs(d__1));
409
p = (d__[l1] - g) / (e[l] * 2.);
410
r__ = pythag(&p, &c_b10);
411
d__[l] = e[l] / (p + d_sign(&r__, &p));
412
d__[l1] = e[l] * (p + d_sign(&r__, &p));
420
for (i__ = l2; i__ <= i__2; ++i__) {
433
for (ii = 1; ii <= i__2; ++ii) {
440
r__ = pythag(&p, &e[i__]);
441
e[i__ + 1] = s * r__;
444
p = c__ * d__[i__] - s * g;
445
d__[i__ + 1] = h__ + s * (c__ * g + s * d__[i__]);
447
for (k = 1; k <= i__3; ++k) {
448
h__ = z__[k + (i__ + 1) * z_dim1];
449
z__[k + (i__ + 1) * z_dim1] = s * z__[k + i__ * z_dim1] + c__
451
z__[k + i__ * z_dim1] = c__ * z__[k + i__ * z_dim1] - s * h__;
456
p = -s * s2 * c3 * el1 * e[l] / dl1;
459
tst2 = tst1 + (d__1 = e[l], abs(d__1));
467
for (ii = 2; ii <= i__1; ++ii) {
473
for (j = ii; j <= i__2; ++j) {
490
for (j = 1; j <= i__2; ++j) {
491
p = z__[j + i__ * z_dim1];
492
z__[j + i__ * z_dim1] = z__[j + k * z_dim1];
493
z__[j + k * z_dim1] = p;
507
void eigen(double **mat,octave_idx_type n,double *eig)
511
OCTAVE_LOCAL_BUFFER (double, trans, (octave_idx_type)nm*nm);
512
OCTAVE_LOCAL_BUFFER (double, off, (octave_idx_type)nm);
514
tred2(&nm,&nm,&mat[0][0],eig,off,trans);
515
tql2(&nm,&nm,eig,off,trans,&ierr);
519
error ("Non converging eigenvalues!");
522
for (octave_idx_type i=0;i<nm;i++)
523
for (octave_idx_type j=0;j<nm;j++)
524
mat[i][j]=trans[i+nm*j];