/*****

*Property of the University of British Columbia (UBC),

*Copyright 2001, by UBC.

*

*By receiving this code, you are agreeing to the following terms:

*1. You will use this code for academic purposes only.

*2. For academic use only, you may distribute the binary or executable code

*   to persons at UBC or the Univ. of Western Australia who have previously 

*   read and agreed to these terms, but you must distribute the SOURCE code

*   with it. 

*3. Each file of source code so distributed must have this header attached.

*4. If the code is revised, the programmer's name and revision date must be added

*   to the Revision List below, as well as the revisions identified in the code.

*5. You will not make this code more widely available via any method such as 

*   publishing in print, email mail-list, usenet posting, website etc.

*6. UBC reserves all rights to this work and all derivative works.

*

*For other proposed purposes please contact:

*The University-Industry Liaison Office 

*IRC Room 331 - 2194 Health Sciences Mall 

*University of British Columbia 

*Vancouver, BC, Canada V6T 1Z3 

*Tel: (604) 822-8580 

*Fax: (604) 822-8589 

*

*or contact: 

*Peter D. Lawrence, Professor at peterl@ece.ubc.ca or 

*Greg Z. Grudic, Assistant Professor, at grudic@cs.colorado.edu

*

*Revision List: 

*Greg Grudic, August 28, 1998.

*****/



/*

%

% File:		svd.c

% Program: 	Functions for Functional Approximation code	

%			

%

% Author:	Greg Grudic 

%

*/


#include <stdio.h>
#include <math.h>
#include "pc.h"

void svd(My_Real **A, My_Real *S2, int n)
{
	int  i, j, k, EstColRank = n, RotCount = n, SweepCount = 0,
		slimit = (n<120) ? 30 : n/4;
	My_Real eps = 1e-15, e2 = 10.0*n*eps*eps, tol = 0.1*eps, vt, p, x0,
		y0, q, r, c0, s0, d1, d2;
	
	for (i=0; i<n; i++)

	{ 

		for (j=0; j<n; j++) A[n+i][j] = 0.0; A[n+i][i] = 1.0; 

	}
	while (RotCount != 0 && SweepCount++ <= slimit)

	{
		RotCount = EstColRank*(EstColRank-1)/2;
		for (j=0; j<EstColRank-1; j++) 
			for (k=j+1; k<EstColRank; k++)

			{
				p = q = r = 0.0;
				for (i=0; i<n; i++)

				{
					x0 = A[i][j]; y0 = A[i][k];
					p += x0*y0; q += x0*x0; r += y0*y0;
				}
				S2[j] = q; S2[k] = r;
				if (q >= r) {
					if (q<=e2*S2[0] || fabs(p)<=tol*q)
						RotCount--;
					else 

					{
						p /= q; r = 1.0-r/q; vt = sqrt(4.0*p*p+r*r);
						c0 = sqrt(0.5*(1.0+r/vt)); s0 = p/(vt*c0);
						for (i=0; i<2*n; i++) 

						{
							d1 = A[i][j]; d2 = A[i][k];
							A[i][j] = d1*c0+d2*s0; A[i][k] = -d1*s0+d2*c0;
						}
					}
				} else 

				{
					p /= r; q = q/r-1.0; vt = sqrt(4.0*p*p+q*q);
					s0 = sqrt(0.5*(1.0-q/vt));
					if (p<0.0) s0 = -s0;
					c0 = p/(vt*s0);
					for (i=0; i<2*n; i++) 

					{
						d1 = A[i][j]; d2 = A[i][k];
						A[i][j] = d1*c0+d2*s0; A[i][k] = -d1*s0+d2*c0;
					}
				}
			}
			while (EstColRank>2 && S2[EstColRank-1]<=S2[0]*tol+tol*tol) EstColRank--;
	}
}
