home *** CD-ROM | disk | FTP | other *** search
- if ( i - l > r - i )
- { stack[++sp] = l; stack[++sp] = i-1; l = i+1; }
- else
- { stack[++sp] = i+1; stack[++sp] = r; r = i-1; }
- }
- if ( sp < 0 )
- break;
- r = stack[sp--]; l = stack[sp--];
- }
- }
-
-
- /* bisvd -- svd of a bidiagonal m x n matrix represented by d (diagonal) and
- f (super-diagonals)
- -- returns with d set to the singular values, f zeroed
- -- if U, V non-NULL, the orthogonal operations are accumulated
- in U, V; if U, V == I on entry, then SVD == U^T.A.V
- where A is initial matrix
- -- returns d on exit */
- VEC *bisvd(d,f,U,V)
- VEC *d, *f;
- MAT *U, *V;
- {
- int i, j, n;
- int i_min, i_max, split;
- Real c, s, shift, size, z;
- Real d_tmp, diff, t11, t12, t22, *d_ve, *f_ve;
-
- if ( ! d || ! f )
- error(E_NULL,"bisvd");
- if ( d->dim != f->dim + 1 )
- error(E_SIZES,"bisvd");
- n = d->dim;
- if ( ( U && U->n < n ) || ( V && V->m < n ) )
- error(E_SIZES,"bisvd");
- if ( ( U && U->m != U->n ) || ( V && V->m != V->n ) )
- error(E_SQUARE,"bisvd");
-
-
- if ( n == 1 )
- return d;
- d_ve = d->ve; f_ve = f->ve;
-
- size = v_norm_inf(d) + v_norm_inf(f);
-
- i_min = 0;
- while ( i_min < n ) /* outer while loop */
- {
- /* find i_max to suit;
- submatrix i_min..i_max should be irreducible */
- i_max = n - 1;
- for ( i = i_min; i < n - 1; i++ )
- if ( d_ve[i] == 0.0 || f_ve[i] == 0.0 )
- { i_max = i;
- if ( f_ve[i] != 0.0 )
- {
- /* have to ``chase'' f[i] element out of matrix */
- z = f_ve[i]; f_ve[i] = 0.0;
- for ( j = i; j < n-1 && z != 0.0; j++ )
- {
- givens(d_ve[j+1],z, &c, &s);
- s = -s;
- d_ve[j+1] = c*d_ve[j+1] - s*z;
- if ( j+1 < n-1 )
- {
- z = s*f_ve[j+1];
- f_ve[j+1] = c*f_ve[j+1];
- }
- if ( U )
- rot_rows(U,i,j+1,c,s,U);
- }
- }
- break;
- }
- if ( i_max <= i_min )
- {
- i_min = i_max + 1;
- continue;
- }
- /* printf("bisvd: i_min = %d, i_max = %d\n",i_min,i_max); */
-
- split = FALSE;
- while ( ! split )
- {
- /* compute shift */
- t11 = d_ve[i_max-1]*d_ve[i_max-1] +
- (i_max > i_min+1 ? f_ve[i_max-2]*f_ve[i_max-2] : 0.0);
- t12 = d_ve[i_max-1]*f_ve[i_max-1];
- t22 = d_ve[i_max]*d_ve[i_max] + f_ve[i_max-1]*f_ve[i_max-1];
- /* use e-val of [[t11,t12],[t12,t22]] matrix
- closest to t22 */
- diff = (t11-t22)/2;
- shift = t22 - t12*t12/(diff +
- sgn(diff)*sqrt(diff*diff+t12*t12));
-
- /* initial Givens' rotation */
- givens(d_ve[i_min]*d_ve[i_min]-shift,
- d_ve[i_min]*f_ve[i_min], &c, &s);
-
- /* do initial Givens' rotations */
- d_tmp = c*d_ve[i_min] + s*f_ve[i_min];
- f_ve[i_min] = c*f_ve[i_min] - s*d_ve[i_min];
- d_ve[i_min] = d_tmp;
- z = s*d_ve[i_min+1];
- d_ve[i_min+1] = c*d_ve[i_min+1];
- if ( V )
- rot_rows(V,i_min,i_min+1,c,s,V);
- /* 2nd Givens' rotation */
- givens(d_ve[i_min],z, &c, &s);
- d_ve[i_min] = c*d_ve[i_min] + s*z;
- d_tmp = c*d_ve[i_min+1] - s*f_ve[i_min];
- f_ve[i_min] = s*d_ve[i_min+1] + c*f_ve[i_min];
- d_ve[i_min+1] = d_tmp;
- if ( i_min+1 < i_max )
- {
- z = s*f_ve[i_min+1];
- f_ve[i_min+1] = c*f_ve[i_min+1];
- }
- if ( U )
- rot_rows(U,i_min,i_min+1,c,s,U);
-
- for ( i = i_min+1; i < i_max; i++ )
- {
- /* get Givens' rotation for zeroing z */
- givens(f_ve[i-1],z, &c, &s);
- f_ve[i-1] = c*f_ve[i-1] + s*z;
- d_tmp = c*d_ve[i] + s*f_ve[i];
- f_ve[i] = c*f_ve[i] - s*d_ve[i];
- d_ve[i] = d_tmp;
- z = s*d_ve[i+1];
- d_ve[i+1] = c*d_ve[i+1];
- if ( V )
- rot_rows(V,i,i+1,c,s,V);
- /* get 2nd Givens' rotation */
- givens(d_ve[i],z, &c, &s);
- d_ve[i] = c*d_ve[i] + s*z;
- d_tmp = c*d_ve[i+1] - s*f_ve[i];
- f_ve[i] = c*f_ve[i] + s*d_ve[i+1];
- d_ve[i+1] = d_tmp;
- if ( i+1 < i_max )
- {
- z = s*f_ve[i+1];
- f_ve[i+1] = c*f_ve[i+1];
- }
- if ( U )
- rot_rows(U,i,i+1,c,s,U);
- }
- /* should matrix be split? */
- for ( i = i_min; i < i_max; i++ )
- if ( fabs(f_ve[i]) <
- MACHEPS*(fabs(d_ve[i])+fabs(d_ve[i+1])) )
- {
- split = TRUE;
- f_ve[i] = 0.0;
- }
- else if ( fabs(d_ve[i]) < MACHEPS*size )
- {
- split = TRUE;
- d_ve[i] = 0.0;
- }
- /* printf("bisvd: d =\n"); v_output(d); */
- /* printf("bisvd: f = \n"); v_output(f); */
- }
- }
- fixsvd(d,U,V);
-
- return d;
- }
-
- /* bifactor -- perform preliminary factorisation for bisvd
- -- updates U and/or V, which ever is not NULL */
- MAT *bifactor(A,U,V)
- MAT *A, *U, *V;
- {
- int k;
- static VEC *tmp1=VNULL, *tmp2=VNULL;
- Real beta;
-
- if ( ! A )
- e