/* nag_dbdsdc (f08mdc) Example Program.
*
* Copyright 2014 Numerical Algorithms Group.
*
* Mark 23, 2011.
*/
#include <stdio.h>
#include <math.h>
#include <nag.h>
#include <nagx02.h>
#include <nagx04.h>
#include <nag_stdlib.h>
#include <nagf08.h>
#include <nagf16.h>
int main(void)
{
/* Scalars */
double alpha, beta, eps, norm;
Integer abi, i, j, k1, k2, leniq, lenq, mlvl, n, pdab, pdb, pdu, pdvt;
Integer exit_status = 0, smlsiz = 25;
/* Arrays */
double *ab = 0, *b = 0, *d = 0, *e = 0, *q = 0, *u = 0, *vt = 0;
Integer *iq = 0;
char nag_enum_arg[40];
/* Nag Types */
NagError fail;
Nag_OrderType order;
Nag_UploType uplo;
Nag_ComputeSingularVecsType compq;
#ifdef NAG_COLUMN_MAJOR
#define B(I, J) b[(J - 1) * pdb + I - 1]
#define U(I, J) u[(J - 1) * pdu + I - 1]
order = Nag_ColMajor;
#else
#define B(I, J) b[(I - 1) * pdb + J - 1]
#define U(I, J) u[(I - 1) * pdu + J - 1]
order = Nag_RowMajor;
#endif
INIT_FAIL(fail);
printf("nag_dbdsdc (f08mdc) Example Program Results\n\n");
/* Skip heading in data file */
scanf("%*[^\n]");
scanf("%ld%*[^\n]", &n);
if (n < 0)
{
printf("Invalid n\n");
exit_status = 1;
goto END;;
}
scanf(" %39s%*[^\n]", nag_enum_arg);
/* nag_enum_name_to_value (x04nac).
* Converts NAG enum member name to value
*/
uplo = (Nag_UploType) nag_enum_name_to_value(nag_enum_arg);
scanf(" %39s%*[^\n]", nag_enum_arg);
/* Starting index for main diagonal in banded storage format = abi. */
if ((order==Nag_ColMajor && uplo==Nag_Lower) ||
(order==Nag_RowMajor && uplo==Nag_Upper)) {
abi = 0;
} else {
abi = 1;
}
compq = (Nag_ComputeSingularVecsType) nag_enum_name_to_value(nag_enum_arg);
/* size of u, vt, q and iq depends on value of compq input */
if (compq==Nag_SingularVecs) {
pdu = n;
pdvt = n;
} else {
pdu = 1;
pdvt = 1;
}
if (compq==Nag_PackedSingularVecs) {
mlvl = (Integer) (log(n/(smlsiz+1.0))/log(2.0)) + 1;
if (mlvl < 1) mlvl = 1;
lenq = MAX(n*n+5*n,n*(3 + 2*smlsiz + 8*mlvl));
leniq = n*3*mlvl;
} else {
lenq = 1;
leniq = 1;
}
pdb = n;
pdab = 2;
/* Allocate memory */
if (!(b = NAG_ALLOC(n*n, double)) ||
!(ab = NAG_ALLOC(pdab*n, double)) ||
!(d = NAG_ALLOC(n, double)) ||
!(e = NAG_ALLOC(n-1, double)) ||
!(q = NAG_ALLOC(lenq, double)) ||
!(u = NAG_ALLOC(pdu*pdu, double)) ||
!(vt = NAG_ALLOC(pdvt*pdvt, double)) ||
!(iq = NAG_ALLOC(leniq, Integer)))
{
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
/* Read the bidiagonal matrix B from data file,
* first the diagonal elements, and then the off-diagonal elements.
*/
for (i = 0; i < n; ++i) scanf("%lf", &d[i]);
scanf("%*[^\n]");
for (i = 0; i < n - 1; ++i) scanf("%lf", &e[i]);
scanf("%*[^\n]");
/* Store diagonal arrays in banded format in ab for printing */
for(i=0; i<n; i++) ab[2*i+abi] = d[i];
for(i=0; i<n-1; i++) ab[2*i+abi+1] = e[i];
/* k1 = lower bandwidth, k2 = upper bandwidth */
k1 = (uplo==Nag_Upper ? 0 : 1);
k2 = 1 - k1;
/* Print Bidiagonal Matrix B stored in ab.
* nag_band_real_mat_print (x04cec).
* Print real packed banded matrix (easy-to-use)
*/
fflush(stdout);
nag_band_real_mat_print(order, n, n, k1, k2, ab, 2, "Matrix B", 0, &fail);
if (fail.code != NE_NOERROR)
{
printf("Error from nag_band_real_mat_print (x04cec).\n%s\n",
fail.message);
exit_status = 1;
goto END;
}
/* Calculate the singular values and left and right singular vectors of B
* using nag_dbdsdc (f08mdc).
*/
nag_dbdsdc(order, uplo, compq, n, d, e, u, pdu, vt, pdvt, q, iq, &fail);
if (fail.code != NE_NOERROR)
{
printf("Error from nag_dbdsdc (f08mdc).\n%s\n", fail.message);
exit_status = 1;
goto END;
}
printf("\nSingular values\n");
for (i = 0; i < n; ++i) printf(" %8.4f%s", d[i], i%8 == 7?"\n":"");
printf("\n\n");
if (compq==Nag_SingularVecs) {
/* Reconstruct bidiagonal matrix from decomposition:
* first, U <- U*S, then Compute B = U*S*V^T.
* nag_dgemm (f16yac).
*/
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++) U(i, j) = U(i, j) * d[j-1];
alpha = 1.0;
beta = 0.0;
nag_dgemm(order, Nag_NoTrans, Nag_NoTrans, n, n, n, alpha, u, pdu,
vt, pdvt, beta, b, pdb, &fail);
if (fail.code != NE_NOERROR)
{
printf("Error from nag_dgemm (f16yac).\n%s\n", fail.message);
exit_status = 1;
goto END;
}
/* Subtract original bidiagonal matrix:
* this should give a matrix close to zero.
*/
for(i=1; i<=n; i++) B(i,i) -= ab[2*i-2+abi];
if (uplo==Nag_Upper)
for(i=1; i<=n-1; i++) B(i,i+1) -= ab[2*i-1+abi];
else
for(i=1; i<=n-1; i++) B(i+1,i) -= ab[2*i-1+abi];
/* nag_dge_norm (f16rac): Find norm of matrix B and print warning if
* it is too large.
*/
nag_dge_norm(order, Nag_OneNorm, n, n, b, pdb, &norm, &fail);
if (fail.code != NE_NOERROR)
{
printf("Error from nag_dge_norm (f16rac).\n%s\n", fail.message);
exit_status = 1;
goto END;
}
/* Get the machine precision, using nag_machine_precision (x02ajc) */
eps = nag_machine_precision;
if (norm > pow(eps,0.8))
{
printf("Norm of B-(U*S*V^T) is much greater than 0.\nSchur "
"factorization has failed.\n norm = %13.4e\n", norm);
}
}
END:
NAG_FREE(ab);
NAG_FREE(b);
NAG_FREE(d);
NAG_FREE(e);
NAG_FREE(q);
NAG_FREE(u);
NAG_FREE(vt);
NAG_FREE(iq);
return exit_status;
}