* Add CX factorization (expert) routines ?GECXX (Reference-LAPACK PR 1161)
1433 lines
42 KiB
C
1433 lines
42 KiB
C
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <complex.h>
|
|
#ifdef complex
|
|
#undef complex
|
|
#endif
|
|
#ifdef I
|
|
#undef I
|
|
#endif
|
|
|
|
#if defined(_WIN64)
|
|
typedef long long BLASLONG;
|
|
typedef unsigned long long BLASULONG;
|
|
#else
|
|
typedef long BLASLONG;
|
|
typedef unsigned long BLASULONG;
|
|
#endif
|
|
|
|
#ifdef LAPACK_ILP64
|
|
typedef BLASLONG blasint;
|
|
#if defined(_WIN64)
|
|
#define blasabs(x) llabs(x)
|
|
#else
|
|
#define blasabs(x) labs(x)
|
|
#endif
|
|
#else
|
|
typedef int blasint;
|
|
#define blasabs(x) abs(x)
|
|
#endif
|
|
|
|
typedef blasint integer;
|
|
|
|
typedef unsigned int uinteger;
|
|
typedef char *address;
|
|
typedef short int shortint;
|
|
typedef float real;
|
|
typedef double doublereal;
|
|
typedef struct { real r, i; } complex;
|
|
typedef struct { doublereal r, i; } doublecomplex;
|
|
#ifdef _MSC_VER
|
|
static inline _Fcomplex Cf(complex *z) {_Fcomplex zz={z->r , z->i}; return zz;}
|
|
static inline _Dcomplex Cd(doublecomplex *z) {_Dcomplex zz={z->r , z->i};return zz;}
|
|
static inline _Fcomplex * _pCf(complex *z) {return (_Fcomplex*)z;}
|
|
static inline _Dcomplex * _pCd(doublecomplex *z) {return (_Dcomplex*)z;}
|
|
#else
|
|
static inline _Complex float Cf(complex *z) {return z->r + z->i*_Complex_I;}
|
|
static inline _Complex double Cd(doublecomplex *z) {return z->r + z->i*_Complex_I;}
|
|
static inline _Complex float * _pCf(complex *z) {return (_Complex float*)z;}
|
|
static inline _Complex double * _pCd(doublecomplex *z) {return (_Complex double*)z;}
|
|
#endif
|
|
#define pCf(z) (*_pCf(z))
|
|
#define pCd(z) (*_pCd(z))
|
|
typedef int logical;
|
|
typedef short int shortlogical;
|
|
typedef char logical1;
|
|
typedef char integer1;
|
|
|
|
#define TRUE_ (1)
|
|
#define FALSE_ (0)
|
|
|
|
/* Extern is for use with -E */
|
|
#ifndef Extern
|
|
#define Extern extern
|
|
#endif
|
|
|
|
/* I/O stuff */
|
|
|
|
typedef int flag;
|
|
typedef int ftnlen;
|
|
typedef int ftnint;
|
|
|
|
/*external read, write*/
|
|
typedef struct
|
|
{ flag cierr;
|
|
ftnint ciunit;
|
|
flag ciend;
|
|
char *cifmt;
|
|
ftnint cirec;
|
|
} cilist;
|
|
|
|
/*internal read, write*/
|
|
typedef struct
|
|
{ flag icierr;
|
|
char *iciunit;
|
|
flag iciend;
|
|
char *icifmt;
|
|
ftnint icirlen;
|
|
ftnint icirnum;
|
|
} icilist;
|
|
|
|
/*open*/
|
|
typedef struct
|
|
{ flag oerr;
|
|
ftnint ounit;
|
|
char *ofnm;
|
|
ftnlen ofnmlen;
|
|
char *osta;
|
|
char *oacc;
|
|
char *ofm;
|
|
ftnint orl;
|
|
char *oblnk;
|
|
} olist;
|
|
|
|
/*close*/
|
|
typedef struct
|
|
{ flag cerr;
|
|
ftnint cunit;
|
|
char *csta;
|
|
} cllist;
|
|
|
|
/*rewind, backspace, endfile*/
|
|
typedef struct
|
|
{ flag aerr;
|
|
ftnint aunit;
|
|
} alist;
|
|
|
|
/* inquire */
|
|
typedef struct
|
|
{ flag inerr;
|
|
ftnint inunit;
|
|
char *infile;
|
|
ftnlen infilen;
|
|
ftnint *inex; /*parameters in standard's order*/
|
|
ftnint *inopen;
|
|
ftnint *innum;
|
|
ftnint *innamed;
|
|
char *inname;
|
|
ftnlen innamlen;
|
|
char *inacc;
|
|
ftnlen inacclen;
|
|
char *inseq;
|
|
ftnlen inseqlen;
|
|
char *indir;
|
|
ftnlen indirlen;
|
|
char *infmt;
|
|
ftnlen infmtlen;
|
|
char *inform;
|
|
ftnint informlen;
|
|
char *inunf;
|
|
ftnlen inunflen;
|
|
ftnint *inrecl;
|
|
ftnint *innrec;
|
|
char *inblank;
|
|
ftnlen inblanklen;
|
|
} inlist;
|
|
|
|
#define VOID void
|
|
|
|
union Multitype { /* for multiple entry points */
|
|
integer1 g;
|
|
shortint h;
|
|
integer i;
|
|
/* longint j; */
|
|
real r;
|
|
doublereal d;
|
|
complex c;
|
|
doublecomplex z;
|
|
};
|
|
|
|
typedef union Multitype Multitype;
|
|
|
|
struct Vardesc { /* for Namelist */
|
|
char *name;
|
|
char *addr;
|
|
ftnlen *dims;
|
|
int type;
|
|
};
|
|
typedef struct Vardesc Vardesc;
|
|
|
|
struct Namelist {
|
|
char *name;
|
|
Vardesc **vars;
|
|
int nvars;
|
|
};
|
|
typedef struct Namelist Namelist;
|
|
|
|
#define abs(x) ((x) >= 0 ? (x) : -(x))
|
|
#define dabs(x) (fabs(x))
|
|
#define f2cmin(a,b) ((a) <= (b) ? (a) : (b))
|
|
#define f2cmax(a,b) ((a) >= (b) ? (a) : (b))
|
|
#define dmin(a,b) (f2cmin(a,b))
|
|
#define dmax(a,b) (f2cmax(a,b))
|
|
#define bit_test(a,b) ((a) >> (b) & 1)
|
|
#define bit_clear(a,b) ((a) & ~((uinteger)1 << (b)))
|
|
#define bit_set(a,b) ((a) | ((uinteger)1 << (b)))
|
|
|
|
#define abort_() { sig_die("Fortran abort routine called", 1); }
|
|
#define c_abs(z) (cabsf(Cf(z)))
|
|
#define c_cos(R,Z) { pCf(R)=ccos(Cf(Z)); }
|
|
#ifdef _MSC_VER
|
|
#define c_div(c, a, b) {Cf(c)._Val[0] = (Cf(a)._Val[0]/Cf(b)._Val[0]); Cf(c)._Val[1]=(Cf(a)._Val[1]/Cf(b)._Val[1]);}
|
|
#define z_div(c, a, b) {Cd(c)._Val[0] = (Cd(a)._Val[0]/Cd(b)._Val[0]); Cd(c)._Val[1]=(Cd(a)._Val[1]/Cd(b)._Val[1]);}
|
|
#else
|
|
#define c_div(c, a, b) {pCf(c) = Cf(a)/Cf(b);}
|
|
#define z_div(c, a, b) {pCd(c) = Cd(a)/Cd(b);}
|
|
#endif
|
|
#define c_exp(R, Z) {pCf(R) = cexpf(Cf(Z));}
|
|
#define c_log(R, Z) {pCf(R) = clogf(Cf(Z));}
|
|
#define c_sin(R, Z) {pCf(R) = csinf(Cf(Z));}
|
|
//#define c_sqrt(R, Z) {*(R) = csqrtf(Cf(Z));}
|
|
#define c_sqrt(R, Z) {pCf(R) = csqrtf(Cf(Z));}
|
|
#define d_abs(x) (fabs(*(x)))
|
|
#define d_acos(x) (acos(*(x)))
|
|
#define d_asin(x) (asin(*(x)))
|
|
#define d_atan(x) (atan(*(x)))
|
|
#define d_atn2(x, y) (atan2(*(x),*(y)))
|
|
#define d_cnjg(R, Z) { pCd(R) = conj(Cd(Z)); }
|
|
#define r_cnjg(R, Z) { pCf(R) = conjf(Cf(Z)); }
|
|
#define d_cos(x) (cos(*(x)))
|
|
#define d_cosh(x) (cosh(*(x)))
|
|
#define d_dim(__a, __b) ( *(__a) > *(__b) ? *(__a) - *(__b) : 0.0 )
|
|
#define d_exp(x) (exp(*(x)))
|
|
#define d_imag(z) (cimag(Cd(z)))
|
|
#define r_imag(z) (cimagf(Cf(z)))
|
|
#define d_int(__x) (*(__x)>0 ? floor(*(__x)) : -floor(- *(__x)))
|
|
#define r_int(__x) (*(__x)>0 ? floor(*(__x)) : -floor(- *(__x)))
|
|
#define d_lg10(x) ( 0.43429448190325182765 * log(*(x)) )
|
|
#define r_lg10(x) ( 0.43429448190325182765 * log(*(x)) )
|
|
#define d_log(x) (log(*(x)))
|
|
#define d_mod(x, y) (fmod(*(x), *(y)))
|
|
#define u_nint(__x) ((__x)>=0 ? floor((__x) + .5) : -floor(.5 - (__x)))
|
|
#define d_nint(x) u_nint(*(x))
|
|
#define u_sign(__a,__b) ((__b) >= 0 ? ((__a) >= 0 ? (__a) : -(__a)) : -((__a) >= 0 ? (__a) : -(__a)))
|
|
#define d_sign(a,b) u_sign(*(a),*(b))
|
|
#define r_sign(a,b) u_sign(*(a),*(b))
|
|
#define d_sin(x) (sin(*(x)))
|
|
#define d_sinh(x) (sinh(*(x)))
|
|
#define d_sqrt(x) (sqrt(*(x)))
|
|
#define d_tan(x) (tan(*(x)))
|
|
#define d_tanh(x) (tanh(*(x)))
|
|
#define i_abs(x) abs(*(x))
|
|
#define i_dnnt(x) ((integer)u_nint(*(x)))
|
|
#define i_len(s, n) (n)
|
|
#define i_nint(x) ((integer)u_nint(*(x)))
|
|
#define i_sign(a,b) ((integer)u_sign((integer)*(a),(integer)*(b)))
|
|
#define pow_dd(ap, bp) ( pow(*(ap), *(bp)))
|
|
#define pow_si(B,E) spow_ui(*(B),*(E))
|
|
#define pow_ri(B,E) spow_ui(*(B),*(E))
|
|
#define pow_di(B,E) dpow_ui(*(B),*(E))
|
|
#define pow_zi(p, a, b) {pCd(p) = zpow_ui(Cd(a), *(b));}
|
|
#define pow_ci(p, a, b) {pCf(p) = cpow_ui(Cf(a), *(b));}
|
|
#define pow_zz(R,A,B) {pCd(R) = cpow(Cd(A),*(B));}
|
|
#define s_cat(lpp, rpp, rnp, np, llp) { ftnlen i, nc, ll; char *f__rp, *lp; ll = (llp); lp = (lpp); for(i=0; i < (int)*(np); ++i) { nc = ll; if((rnp)[i] < nc) nc = (rnp)[i]; ll -= nc; f__rp = (rpp)[i]; while(--nc >= 0) *lp++ = *(f__rp)++; } while(--ll >= 0) *lp++ = ' '; }
|
|
#define s_cmp(a,b,c,d) ((integer)strncmp((a),(b),f2cmin((c),(d))))
|
|
#define s_copy(A,B,C,D) { int __i,__m; for (__i=0, __m=f2cmin((C),(D)); __i<__m && (B)[__i] != 0; ++__i) (A)[__i] = (B)[__i]; }
|
|
#define sig_die(s, kill) { exit(1); }
|
|
#define s_stop(s, n) {exit(0);}
|
|
static char junk[] = "\n@(#)LIBF77 VERSION 19990503\n";
|
|
#define z_abs(z) (cabs(Cd(z)))
|
|
#define z_exp(R, Z) {pCd(R) = cexp(Cd(Z));}
|
|
#define z_sqrt(R, Z) {pCd(R) = csqrt(Cd(Z));}
|
|
#define myexit_() break;
|
|
#define mycycle_() continue;
|
|
#define myceiling_(w) {ceil(w)}
|
|
#define myhuge_(w) {HUGE_VAL}
|
|
//#define mymaxloc_(w,s,e,n) {if (sizeof(*(w)) == sizeof(double)) dmaxloc_((w),*(s),*(e),n); else dmaxloc_((w),*(s),*(e),n);}
|
|
#define mymaxloc_(w,s,e,n) dmaxloc_(w,*(s),*(e),n)
|
|
|
|
/* procedure parameter types for -A and -C++ */
|
|
|
|
#define F2C_proc_par_types 1
|
|
#ifdef __cplusplus
|
|
typedef logical (*L_fp)(...);
|
|
#else
|
|
typedef logical (*L_fp)();
|
|
#endif
|
|
|
|
static float spow_ui(float x, integer n) {
|
|
float pow=1.0; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x = 1/x;
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow *= x;
|
|
if(u >>= 1) x *= x;
|
|
else break;
|
|
}
|
|
}
|
|
return pow;
|
|
}
|
|
static double dpow_ui(double x, integer n) {
|
|
double pow=1.0; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x = 1/x;
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow *= x;
|
|
if(u >>= 1) x *= x;
|
|
else break;
|
|
}
|
|
}
|
|
return pow;
|
|
}
|
|
#ifdef _MSC_VER
|
|
static _Fcomplex cpow_ui(complex x, integer n) {
|
|
complex pow={1.0,0.0}; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x.r = 1/x.r, x.i=1/x.i;
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow.r *= x.r, pow.i *= x.i;
|
|
if(u >>= 1) x.r *= x.r, x.i *= x.i;
|
|
else break;
|
|
}
|
|
}
|
|
_Fcomplex p={pow.r, pow.i};
|
|
return p;
|
|
}
|
|
#else
|
|
static _Complex float cpow_ui(_Complex float x, integer n) {
|
|
_Complex float pow=1.0; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x = 1/x;
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow *= x;
|
|
if(u >>= 1) x *= x;
|
|
else break;
|
|
}
|
|
}
|
|
return pow;
|
|
}
|
|
#endif
|
|
#ifdef _MSC_VER
|
|
static _Dcomplex zpow_ui(_Dcomplex x, integer n) {
|
|
_Dcomplex pow={1.0,0.0}; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x._Val[0] = 1/x._Val[0], x._Val[1] =1/x._Val[1];
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow._Val[0] *= x._Val[0], pow._Val[1] *= x._Val[1];
|
|
if(u >>= 1) x._Val[0] *= x._Val[0], x._Val[1] *= x._Val[1];
|
|
else break;
|
|
}
|
|
}
|
|
_Dcomplex p = {pow._Val[0], pow._Val[1]};
|
|
return p;
|
|
}
|
|
#else
|
|
static _Complex double zpow_ui(_Complex double x, integer n) {
|
|
_Complex double pow=1.0; unsigned long int u;
|
|
if(n != 0) {
|
|
if(n < 0) n = -n, x = 1/x;
|
|
for(u = n; ; ) {
|
|
if(u & 01) pow *= x;
|
|
if(u >>= 1) x *= x;
|
|
else break;
|
|
}
|
|
}
|
|
return pow;
|
|
}
|
|
#endif
|
|
static integer pow_ii(integer x, integer n) {
|
|
integer pow; unsigned long int u;
|
|
if (n <= 0) {
|
|
if (n == 0 || x == 1) pow = 1;
|
|
else if (x != -1) pow = x == 0 ? 1/x : 0;
|
|
else n = -n;
|
|
}
|
|
if ((n > 0) || !(n == 0 || x == 1 || x != -1)) {
|
|
u = n;
|
|
for(pow = 1; ; ) {
|
|
if(u & 01) pow *= x;
|
|
if(u >>= 1) x *= x;
|
|
else break;
|
|
}
|
|
}
|
|
return pow;
|
|
}
|
|
static integer dmaxloc_(double *w, integer s, integer e, integer *n)
|
|
{
|
|
double m; integer i, mi;
|
|
for(m=w[s-1], mi=s, i=s+1; i<=e; i++)
|
|
if (w[i-1]>m) mi=i ,m=w[i-1];
|
|
return mi-s+1;
|
|
}
|
|
static integer smaxloc_(float *w, integer s, integer e, integer *n)
|
|
{
|
|
float m; integer i, mi;
|
|
for(m=w[s-1], mi=s, i=s+1; i<=e; i++)
|
|
if (w[i-1]>m) mi=i ,m=w[i-1];
|
|
return mi-s+1;
|
|
}
|
|
static inline void cdotc_(complex *z, integer *n_, complex *x, integer *incx_, complex *y, integer *incy_) {
|
|
integer n = *n_, incx = *incx_, incy = *incy_, i;
|
|
#ifdef _MSC_VER
|
|
_Fcomplex zdotc = {0.0, 0.0};
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += conjf(Cf(&x[i]))._Val[0] * Cf(&y[i])._Val[0];
|
|
zdotc._Val[1] += conjf(Cf(&x[i]))._Val[1] * Cf(&y[i])._Val[1];
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += conjf(Cf(&x[i*incx]))._Val[0] * Cf(&y[i*incy])._Val[0];
|
|
zdotc._Val[1] += conjf(Cf(&x[i*incx]))._Val[1] * Cf(&y[i*incy])._Val[1];
|
|
}
|
|
}
|
|
pCf(z) = zdotc;
|
|
}
|
|
#else
|
|
_Complex float zdotc = 0.0;
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += conjf(Cf(&x[i])) * Cf(&y[i]);
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += conjf(Cf(&x[i*incx])) * Cf(&y[i*incy]);
|
|
}
|
|
}
|
|
pCf(z) = zdotc;
|
|
}
|
|
#endif
|
|
static inline void zdotc_(doublecomplex *z, integer *n_, doublecomplex *x, integer *incx_, doublecomplex *y, integer *incy_) {
|
|
integer n = *n_, incx = *incx_, incy = *incy_, i;
|
|
#ifdef _MSC_VER
|
|
_Dcomplex zdotc = {0.0, 0.0};
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += conj(Cd(&x[i]))._Val[0] * Cd(&y[i])._Val[0];
|
|
zdotc._Val[1] += conj(Cd(&x[i]))._Val[1] * Cd(&y[i])._Val[1];
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += conj(Cd(&x[i*incx]))._Val[0] * Cd(&y[i*incy])._Val[0];
|
|
zdotc._Val[1] += conj(Cd(&x[i*incx]))._Val[1] * Cd(&y[i*incy])._Val[1];
|
|
}
|
|
}
|
|
pCd(z) = zdotc;
|
|
}
|
|
#else
|
|
_Complex double zdotc = 0.0;
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += conj(Cd(&x[i])) * Cd(&y[i]);
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += conj(Cd(&x[i*incx])) * Cd(&y[i*incy]);
|
|
}
|
|
}
|
|
pCd(z) = zdotc;
|
|
}
|
|
#endif
|
|
static inline void cdotu_(complex *z, integer *n_, complex *x, integer *incx_, complex *y, integer *incy_) {
|
|
integer n = *n_, incx = *incx_, incy = *incy_, i;
|
|
#ifdef _MSC_VER
|
|
_Fcomplex zdotc = {0.0, 0.0};
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += Cf(&x[i])._Val[0] * Cf(&y[i])._Val[0];
|
|
zdotc._Val[1] += Cf(&x[i])._Val[1] * Cf(&y[i])._Val[1];
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += Cf(&x[i*incx])._Val[0] * Cf(&y[i*incy])._Val[0];
|
|
zdotc._Val[1] += Cf(&x[i*incx])._Val[1] * Cf(&y[i*incy])._Val[1];
|
|
}
|
|
}
|
|
pCf(z) = zdotc;
|
|
}
|
|
#else
|
|
_Complex float zdotc = 0.0;
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += Cf(&x[i]) * Cf(&y[i]);
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += Cf(&x[i*incx]) * Cf(&y[i*incy]);
|
|
}
|
|
}
|
|
pCf(z) = zdotc;
|
|
}
|
|
#endif
|
|
static inline void zdotu_(doublecomplex *z, integer *n_, doublecomplex *x, integer *incx_, doublecomplex *y, integer *incy_) {
|
|
integer n = *n_, incx = *incx_, incy = *incy_, i;
|
|
#ifdef _MSC_VER
|
|
_Dcomplex zdotc = {0.0, 0.0};
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += Cd(&x[i])._Val[0] * Cd(&y[i])._Val[0];
|
|
zdotc._Val[1] += Cd(&x[i])._Val[1] * Cd(&y[i])._Val[1];
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc._Val[0] += Cd(&x[i*incx])._Val[0] * Cd(&y[i*incy])._Val[0];
|
|
zdotc._Val[1] += Cd(&x[i*incx])._Val[1] * Cd(&y[i*incy])._Val[1];
|
|
}
|
|
}
|
|
pCd(z) = zdotc;
|
|
}
|
|
#else
|
|
_Complex double zdotc = 0.0;
|
|
if (incx == 1 && incy == 1) {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += Cd(&x[i]) * Cd(&y[i]);
|
|
}
|
|
} else {
|
|
for (i=0;i<n;i++) { /* zdotc = zdotc + dconjg(x(i))* y(i) */
|
|
zdotc += Cd(&x[i*incx]) * Cd(&y[i*incy]);
|
|
}
|
|
}
|
|
pCd(z) = zdotc;
|
|
}
|
|
#endif
|
|
/* -- translated by f2c (version 20000121).
|
|
You must link the resulting object file with the libraries:
|
|
-lf2c -lm (in that order)
|
|
*/
|
|
|
|
|
|
|
|
/* -- translated by f2c (version 20200916).
|
|
You must link the resulting object file with libf2c:
|
|
on Microsoft Windows system, link with libf2c.lib;
|
|
on Linux or Unix systems, link with .../path/to/libf2c.a -lm
|
|
or, if you install libf2c.a in a standard place, with -lf2c -lm
|
|
-- in that order, at the end of the command line, as in
|
|
cc *.o -lf2c -lm
|
|
Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,
|
|
|
|
http://www.netlib.org/f2c/libf2c.zip
|
|
*/
|
|
|
|
|
|
|
|
/* Table of constant values */
|
|
|
|
static integer c_n1 = -1;
|
|
static integer c__0 = 0;
|
|
static doublereal c_b15 = -1.;
|
|
static integer c__1 = 1;
|
|
|
|
/* Subroutine */ int dgecxx_(char *fact, char *usesd, integer *m, integer *n,
|
|
integer *desel_rows__, integer *sel_desel_cols__, integer *kmaxfree,
|
|
doublereal *abstol, doublereal *reltol, doublereal *a, integer *lda,
|
|
integer *k, doublereal *maxc2nrmk, doublereal *relmaxc2nrmk,
|
|
doublereal *fnrmk, integer *ipiv, integer *jpiv, doublereal *tau,
|
|
doublereal *c__, integer *ldc, doublereal *qrc, integer *ldqrc,
|
|
doublereal *x, integer *ldx, doublereal *work, integer *lwork,
|
|
integer *iwork, integer *liwork, integer *info)
|
|
{
|
|
/* System generated locals */
|
|
integer a_dim1, a_offset, c_dim1, c_offset, qrc_dim1, qrc_offset, x_dim1,
|
|
x_offset, i__1, i__2, i__3;
|
|
doublereal d__1, d__2;
|
|
|
|
/* Local variables */
|
|
doublereal maxc2nrm, relmaxc2nrmkfree;
|
|
integer i__, j, minmnfree, ip, jp;
|
|
doublereal abstolfree;
|
|
integer kp0;
|
|
doublereal reltolfree;
|
|
logical use_sel_desel_cols__;
|
|
doublereal eps;
|
|
integer nsel, msub, nsub;
|
|
extern doublereal dnrm2_(integer *, doublereal *, integer *);
|
|
integer kfree, mfree, nfree;
|
|
extern /* Subroutine */ int dgels_(char *, integer *, integer *, integer *
|
|
, doublereal *, integer *, doublereal *, integer *, doublereal *,
|
|
integer *, integer *);
|
|
extern logical lsame_(char *, char *);
|
|
doublereal maxc2nrmkfree;
|
|
integer iinfo, itemp, minmn;
|
|
extern /* Subroutine */ int dcopy_(integer *, doublereal *, integer *,
|
|
doublereal *, integer *), dswap_(integer *, doublereal *, integer
|
|
*, doublereal *, integer *);
|
|
extern doublereal dlamch_(char *), dlange_(char *, integer *,
|
|
integer *, doublereal *, integer *, doublereal *);
|
|
extern integer idamax_(integer *, doublereal *, integer *);
|
|
integer jdesel;
|
|
extern /* Subroutine */ int dgeqrf_(integer *, integer *, doublereal *,
|
|
integer *, doublereal *, doublereal *, integer *, integer *);
|
|
integer mdesel, ndesel;
|
|
extern /* Subroutine */ int dlacpy_(char *, integer *, integer *,
|
|
doublereal *, integer *, doublereal *, integer *);
|
|
doublereal safmin;
|
|
extern /* Subroutine */ int xerbla_(char *, integer *);
|
|
extern logical disnan_(doublereal *);
|
|
integer mresid, nresid, kmaxls, lwkmin;
|
|
extern /* Subroutine */ int dormqr_(char *, char *, integer *, integer *,
|
|
integer *, doublereal *, integer *, doublereal *, doublereal *,
|
|
integer *, doublereal *, integer *, integer *);
|
|
logical usetol;
|
|
integer lwkopt;
|
|
logical lquery, use_desel_rows__;
|
|
integer liwkmin;
|
|
logical returnc;
|
|
integer liwkopt;
|
|
logical returnx;
|
|
extern /* Subroutine */ int dgeqp3rk_(integer *, integer *, integer *,
|
|
integer *, doublereal *, doublereal *, doublereal *, integer *,
|
|
integer *, doublereal *, doublereal *, integer *, doublereal *,
|
|
doublereal *, integer *, integer *, integer *);
|
|
|
|
|
|
/* -- LAPACK computational routine -- */
|
|
/* -- LAPACK is a software package provided by Univ. of Tennessee, -- */
|
|
/* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
|
|
/* Test the input arguments */
|
|
|
|
/* Parameter adjustments */
|
|
--desel_rows__;
|
|
--sel_desel_cols__;
|
|
a_dim1 = *lda;
|
|
a_offset = 1 + a_dim1;
|
|
a -= a_offset;
|
|
--ipiv;
|
|
--jpiv;
|
|
--tau;
|
|
c_dim1 = *ldc;
|
|
c_offset = 1 + c_dim1;
|
|
c__ -= c_offset;
|
|
qrc_dim1 = *ldqrc;
|
|
qrc_offset = 1 + qrc_dim1;
|
|
qrc -= qrc_offset;
|
|
x_dim1 = *ldx;
|
|
x_offset = 1 + x_dim1;
|
|
x -= x_offset;
|
|
--work;
|
|
--iwork;
|
|
|
|
/* Function Body */
|
|
*info = 0;
|
|
mdesel = 0;
|
|
nsel = 0;
|
|
ndesel = 0;
|
|
msub = *m;
|
|
nsub = *n;
|
|
mfree = msub;
|
|
nfree = nsub;
|
|
minmn = f2cmin(*m,*n);
|
|
|
|
lquery = *lwork == -1 || *liwork == -1;
|
|
|
|
returnx = lsame_(fact, "X");
|
|
returnc = lsame_(fact, "C") || returnx;
|
|
|
|
use_desel_rows__ = lsame_(usesd, "R") || lsame_(
|
|
usesd, "A");
|
|
use_sel_desel_cols__ = lsame_(usesd, "C") || lsame_(
|
|
usesd, "A");
|
|
|
|
if (! (returnc || lsame_(fact, "P"))) {
|
|
*info = -1;
|
|
} else if (! (use_desel_rows__ || use_sel_desel_cols__ || lsame_(usesd,
|
|
"N"))) {
|
|
*info = -2;
|
|
} else if (*m < 0) {
|
|
*info = -3;
|
|
} else if (*n < 0) {
|
|
*info = -4;
|
|
} else {
|
|
|
|
/* This is to check that the number of preselected columns NSEL */
|
|
/* cannot be larger than MSUB, which is the number of rows */
|
|
/* without MDESEL deselected rows. When the number of */
|
|
/* preselected columns NSEL is larger than MSUB, */
|
|
/* the factorization of all preselected NSEL columns cannot be */
|
|
/* completed. MSUB also will be used for LDX argument check */
|
|
/* later. */
|
|
|
|
if (use_desel_rows__) {
|
|
|
|
/* Count the number of free rows MSUB. */
|
|
|
|
i__1 = *m;
|
|
for (i__ = 1; i__ <= i__1; ++i__) {
|
|
if (desel_rows__[i__] == -1) {
|
|
++mdesel;
|
|
}
|
|
}
|
|
msub = *m - mdesel;
|
|
mfree = msub;
|
|
}
|
|
|
|
if (use_sel_desel_cols__) {
|
|
|
|
/* Count the number of preselected columns NSEL and the */
|
|
/* number of preselected and free columns NSUB = N - NDESEL. */
|
|
|
|
i__1 = *n;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
if (sel_desel_cols__[j] == 1) {
|
|
++nsel;
|
|
}
|
|
if (sel_desel_cols__[j] == -1) {
|
|
++ndesel;
|
|
}
|
|
}
|
|
nsub = *n - ndesel;
|
|
mfree = msub - nsel;
|
|
nfree = nsub - nsel;
|
|
|
|
}
|
|
minmnfree = f2cmin(mfree,nfree);
|
|
|
|
if (nsel > msub) {
|
|
*info = -6;
|
|
} else if (*kmaxfree < 0) {
|
|
*info = -7;
|
|
} else if (disnan_(abstol)) {
|
|
*info = -8;
|
|
} else if (disnan_(reltol)) {
|
|
*info = -9;
|
|
} else if (*lda < f2cmax(1,*m)) {
|
|
*info = -11;
|
|
/* This is a check for LDC */
|
|
} else if (returnc && *ldc < f2cmax(1,*m) || ! returnc && *ldc < 1) {
|
|
*info = -20;
|
|
/* This is a check for LDQRC */
|
|
} else if (returnx && *ldqrc < f2cmax(1,*m) || ! returnx && *ldqrc < 1) {
|
|
*info = -22;
|
|
/* This is a check for LDX */
|
|
} else if (returnx && *ldx < f2cmax(1,*m) || ! returnx && *ldx < 1) {
|
|
*info = -24;
|
|
}
|
|
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
/* a) Test the input workspace size LWORK and LIWORK for the */
|
|
/* minimum size requirement LWKMIN and LIWKMIN respectively. */
|
|
/* b) Determine the optimal workspace sizes LWKOPT and LIWKOPT to */
|
|
/* be returned in WORK( 1 ) and IWORK( 1 ) respectively, */
|
|
/* if INFO >= 0 in cases: */
|
|
/* (1) LQUERY = .TRUE., */
|
|
/* (2) when the routine exits. */
|
|
/* Here, LWKMIN and LIWKMIN are the minimum workspaces required for */
|
|
/* unblocked code. */
|
|
|
|
if (*info == 0) {
|
|
if (minmn == 0) {
|
|
lwkmin = 1;
|
|
lwkopt = 1;
|
|
liwkmin = 1;
|
|
liwkopt = 1;
|
|
} else {
|
|
|
|
/* (Real_wk_part_1) Real minimum and optimal workspace */
|
|
/* computation. */
|
|
/* LWKMIN = MAX(1, NSUB) for column 2-norm computation */
|
|
|
|
lwkmin = f2cmax(1,nsub);
|
|
lwkopt = lwkmin;
|
|
|
|
/* (Int_wk_part_1) Integer minimum workspace computation. */
|
|
|
|
liwkmin = 1;
|
|
|
|
/* Call of DGEQRF. */
|
|
|
|
if (nsel > 0) {
|
|
|
|
/* (Real_wk_part_2) Real minimum workspace computation. */
|
|
/* LWKMIN = MAX(1, NSEL) for the call of DGEQRF. */
|
|
/* We can skip counting this workspace as */
|
|
/* LWKMIN = MAX( LWKMIN, NSEL ), since NSEL <= NSUB. */
|
|
|
|
/* Query for optimal workspace size for DGEQRF. */
|
|
|
|
dgeqrf_(&msub, &nsel, &a[a_offset], lda, &tau[1], &work[1], &
|
|
c_n1, &iinfo);
|
|
/* Computing MAX */
|
|
i__1 = lwkopt, i__2 = (integer) work[1];
|
|
lwkopt = f2cmax(i__1,i__2);
|
|
|
|
/* Call of DORMQR. */
|
|
|
|
if (nfree > 0) {
|
|
|
|
/* (Real_wk_part_3) Real minimum workspace computation. */
|
|
/* NOTE: minimum workspace requirement for DORMQR */
|
|
/* LWKMIN = MAX(1, NFREE) is smaller than NSUB */
|
|
/* and it is smaller than LWKMIN = 3*NFREE-1 for */
|
|
/* DGEQP3RK. We can skip counting this workspace as */
|
|
/* as LWKMIN = MAX( LWKMIN, NFREE ). */
|
|
|
|
/* Query for optimal workspace size for DORMQR. */
|
|
|
|
dormqr_("L", "T", &msub, &nfree, &nsel, &a[a_offset], lda,
|
|
&tau[1], &a[(nsel + 1) * a_dim1 + 1], lda, &work[
|
|
1], &c_n1, &iinfo);
|
|
/* Computing MAX */
|
|
i__1 = lwkopt, i__2 = (integer) work[1];
|
|
lwkopt = f2cmax(i__1,i__2);
|
|
}
|
|
|
|
}
|
|
|
|
/* Call of DGEQP3RK. */
|
|
|
|
if (minmnfree != 0) {
|
|
|
|
/* (Real_wk_part_4) Real minimum workspace computation. */
|
|
/* LWKMIN = MAX(1, 3*NFREE-1) for the call of DGEQP3RK. */
|
|
|
|
/* Computing MAX */
|
|
i__1 = lwkmin, i__2 = nfree * 3 - 1;
|
|
lwkmin = f2cmax(i__1,i__2);
|
|
|
|
/* Query for optimal workspace size for DGEQP3RK. */
|
|
|
|
dgeqp3rk_(&mfree, &nfree, &c__0, &nfree, &c_b15, &c_b15, &a[
|
|
a_dim1 + 1], lda, &kfree, &maxc2nrmkfree, &
|
|
relmaxc2nrmkfree, &jpiv[1], &tau[1], &work[1], &c_n1,
|
|
&iwork[1], &iinfo);
|
|
/* Computing MAX */
|
|
i__1 = lwkopt, i__2 = (integer) work[1];
|
|
lwkopt = f2cmax(i__1,i__2);
|
|
|
|
/* (Int_wk_part_2) Integer minimum workspace computation. */
|
|
/* LIWKMIN = NFREE-1 for the call of DGEQP3RK. */
|
|
|
|
/* Computing MAX */
|
|
i__1 = liwkmin, i__2 = nfree - 1;
|
|
liwkmin = f2cmax(i__1,i__2);
|
|
|
|
if (nsel != 0) {
|
|
|
|
/* (Int_wk_part_3) Integer minimum workspace computation. */
|
|
/* NFREE is for DGEQP3RK and NFREE-1 for JPIV adjustment. */
|
|
|
|
/* Computing MAX */
|
|
i__1 = liwkmin, i__2 = nfree + nfree - 1;
|
|
liwkmin = f2cmax(i__1,i__2);
|
|
}
|
|
|
|
}
|
|
|
|
if (returnc) {
|
|
|
|
/* Integer minimum workspace computation. */
|
|
/* (Int_wk_part_4) LIWKMIN = 2*N for applying the */
|
|
/* interchanges for the columns in the matrix C. */
|
|
|
|
/* Computing MAX */
|
|
i__1 = liwkmin, i__2 = *n << 1;
|
|
liwkmin = f2cmax(i__1,i__2);
|
|
}
|
|
|
|
/* Integer optimal workspace computation. */
|
|
|
|
liwkopt = liwkmin;
|
|
|
|
/* Call of DGELS. */
|
|
|
|
if (returnx) {
|
|
|
|
/* (Real_wk_part_5) Real minimum workspace computation. */
|
|
/* LWKMIN = f2cmax( 1, MINMN + f2cmax( MINMN, N ) ) = */
|
|
/* = f2cmax( 1, MINMN + N ) for the call of DGELS. */
|
|
|
|
/* Computing MAX */
|
|
i__1 = lwkmin, i__2 = minmn + *n;
|
|
lwkmin = f2cmax(i__1,i__2);
|
|
|
|
/* Query for optimal workspace size for DGELS. */
|
|
|
|
kmaxls = minmn;
|
|
|
|
dgels_("N", m, &kmaxls, n, &qrc[qrc_offset], ldqrc, &x[
|
|
x_offset], ldx, &work[1], &c_n1, &iinfo);
|
|
/* Computing MAX */
|
|
i__1 = lwkopt, i__2 = (integer) work[1];
|
|
lwkopt = f2cmax(i__1,i__2);
|
|
|
|
}
|
|
|
|
/* End of ELSE for IF( MINMN.EQ.0 ) */
|
|
|
|
}
|
|
|
|
if (*lwork < lwkmin && ! lquery) {
|
|
*info = -26;
|
|
} else if (*liwork < liwkmin && ! lquery) {
|
|
*info = -28;
|
|
}
|
|
}
|
|
|
|
if (*info == 0) {
|
|
work[1] = (doublereal) lwkopt;
|
|
iwork[1] = liwkopt;
|
|
}
|
|
|
|
if (*info != 0) {
|
|
i__1 = -(*info);
|
|
xerbla_("DGECXX", &i__1);
|
|
return 0;
|
|
} else if (lquery) {
|
|
return 0;
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Quick return if possible for: */
|
|
/* a) M = 0 or N = 0. There is no matrix A(1:M,1:N). */
|
|
/* b) MSUB = 0 or NSUB = 0. There is no matrix A_sub(1:MSUB,1:NSUB). */
|
|
/* NOTE: f2cmin( M, N) = 0 implies f2cmin( MSUB, NSUB) = 0. */
|
|
/* We need to return correct values for all scalar output parameters, */
|
|
/* (including WORK(1) and IWORK(1), which are set above). */
|
|
|
|
if (f2cmin(msub,nsub) == 0) {
|
|
*k = 0;
|
|
*maxc2nrmk = 0.;
|
|
*relmaxc2nrmk = 0.;
|
|
*fnrmk = 0.;
|
|
return 0;
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
*k = 0;
|
|
|
|
/* If we need to return factor X, copy the original untouched matrix */
|
|
/* A into the array X. */
|
|
|
|
if (returnx) {
|
|
dlacpy_("F", m, n, &a[a_offset], lda, &x[x_offset], ldx);
|
|
}
|
|
|
|
/* If we need to return the factor C, copy the original matrix A */
|
|
/* into the array C, only if do not return the factor X. In this */
|
|
/* case, we need to choose the columns of the matrix A in the array C */
|
|
/* in place, otherwise we can copy the columns of the matrix A from */
|
|
/* the array X. */
|
|
|
|
if (returnc && ! returnx) {
|
|
dlacpy_("F", m, n, &a[a_offset], lda, &c__[c_offset], ldc);
|
|
}
|
|
|
|
/* ================================================================== */
|
|
/* Permute the deselected rows to the bottom of the matrix A. */
|
|
/* 1) The initial order of included rows in their block is preserved. */
|
|
/* 2) The initial order of deselected rows in their block is not */
|
|
/* preserved. */
|
|
/* ================================================================== */
|
|
|
|
/* I is an index of DESEL_ROWS array and a row index of */
|
|
/* the matrix A. MSUB is the number of processed included rows, which */
|
|
/* is also an index pointer to the last included row in the matrix A. */
|
|
/* We can think of I as a row source index, and MSUB as a destination */
|
|
/* index for moving an included row in the matrix A. */
|
|
|
|
/* ( We start with MSUB = 0. We loop over index I in (1:M), and */
|
|
/* for each position I in DESEL_ROWS array, we check if the row at */
|
|
/* the position I in the matrix A is an included row (not -1 value). */
|
|
/* If it is an included row, we increment MSUB pointer, otherwise */
|
|
/* we do not change MSUB index pointer. Then, we bring this included */
|
|
/* row from the index I in the matrix A into smaller (or same) */
|
|
/* MSUB index in the matrix A. If I = MSUB, then the included row */
|
|
/* is already in place. Due to row swap, the deselected row */
|
|
/* at MSUB index will move into I index in the matrix A. In this way, */
|
|
/* we move all the included rows to the top matrix block preserving */
|
|
/* their initial order within the included block. The initial order */
|
|
/* of deselected rows will not be preserved within their block. */
|
|
|
|
if (use_desel_rows__) {
|
|
|
|
msub = 0;
|
|
i__1 = *m;
|
|
for (i__ = 1; i__ <= i__1; ++i__) {
|
|
|
|
/* Initialize the row pivot array IPIV. */
|
|
ipiv[i__] = i__;
|
|
|
|
/* The row at the index I is an included row and should be */
|
|
/* moved to the top of the matrix A. */
|
|
|
|
if (desel_rows__[i__] != -1) {
|
|
++msub;
|
|
|
|
/* This is a check whether the included row is */
|
|
/* on the included place already. */
|
|
|
|
if (i__ != msub) {
|
|
|
|
/* Here, we swap A(I,1:N) into A(MSUB,1:N). */
|
|
|
|
dswap_(n, &a[i__ + a_dim1], lda, &a[msub + a_dim1], lda);
|
|
|
|
/* Save the interchange. */
|
|
|
|
ipiv[i__] = ipiv[msub];
|
|
ipiv[msub] = i__;
|
|
desel_rows__[msub] = desel_rows__[i__];
|
|
desel_rows__[i__] = -1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* We do not use the row deselection DESEL_ROWS array. */
|
|
/* Initialize the row pivot array IPIV. */
|
|
/* NOTE: MSUB=M has default value, */
|
|
/* which is set at the beginning of the routine, before argument */
|
|
/* checks. */
|
|
|
|
i__1 = *m;
|
|
for (i__ = 1; i__ <= i__1; ++i__) {
|
|
ipiv[i__] = i__;
|
|
}
|
|
}
|
|
|
|
/* ================================================================== */
|
|
/* Permute the preselected columns to the left and deselected */
|
|
/* columns to the right of the matrix A. */
|
|
/* 1) The order of preselected columns is preserved. */
|
|
/* 2) The order of free columns is not preserved. */
|
|
/* 3) The order of deselected columns is not preserved. */
|
|
/* ================================================================== */
|
|
|
|
/* J is the index of SEL_DESEL_COLS array and column J */
|
|
/* of the matrix A. */
|
|
|
|
if (use_sel_desel_cols__) {
|
|
|
|
/* Column selection. */
|
|
/* NSEL is the number of selected columns, also the pointer to */
|
|
/* the last selected column. */
|
|
|
|
nsel = 0;
|
|
i__1 = *n;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
|
|
/* Initialize column pivot array JPIV. */
|
|
jpiv[j] = j;
|
|
|
|
if (sel_desel_cols__[j] == 1) {
|
|
++nsel;
|
|
|
|
/* This is the check whether the selected column is */
|
|
/* on the selected place already. */
|
|
|
|
if (j != nsel) {
|
|
|
|
/* Here, we swap the column A(1:M,J) into A(1:M,NSEL) */
|
|
|
|
dswap_(m, &a[j * a_dim1 + 1], &c__1, &a[nsel * a_dim1 + 1]
|
|
, &c__1);
|
|
jpiv[j] = jpiv[nsel];
|
|
jpiv[nsel] = j;
|
|
sel_desel_cols__[j] = sel_desel_cols__[nsel];
|
|
sel_desel_cols__[nsel] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Column deselection. */
|
|
/* JDESEL the pointer to the last */
|
|
/* deselected column counting right-to-left. */
|
|
|
|
jdesel = *n + 1;
|
|
i__1 = nsel + 1;
|
|
for (j = *n; j >= i__1; --j) {
|
|
if (sel_desel_cols__[j] == -1) {
|
|
--jdesel;
|
|
|
|
/* This is the check whether the deselected column is */
|
|
/* on the deselected place already. */
|
|
|
|
if (j != jdesel) {
|
|
|
|
/* Here, we swap the column A(1:M,J) into A(1:M,JDESEL) */
|
|
|
|
dswap_(m, &a[j * a_dim1 + 1], &c__1, &a[jdesel * a_dim1 +
|
|
1], &c__1);
|
|
itemp = jpiv[j];
|
|
jpiv[j] = jpiv[jdesel];
|
|
jpiv[jdesel] = itemp;
|
|
sel_desel_cols__[j] = sel_desel_cols__[jdesel];
|
|
sel_desel_cols__[jdesel] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
nsub = jdesel - 1;
|
|
|
|
} else {
|
|
|
|
/* We do not use the column selection deselection */
|
|
/* SEL_DESEL_COLS array. */
|
|
/* Initialize column pivot array JPIV. */
|
|
/* NOTE: NSUB=N has default value, */
|
|
/* which is set at the beginning of the routine, before argument */
|
|
/* checks. */
|
|
|
|
i__1 = *n;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
jpiv[j] = j;
|
|
}
|
|
|
|
}
|
|
|
|
/* ================================================================== */
|
|
/* Compute the complete column 2-norms of the submatrix */
|
|
/* A_sub = A(1:MSUB, 1:NSUB) and store them in WORK(1:NSUB). */
|
|
|
|
i__1 = nsub;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
work[j] = dnrm2_(&msub, &a[j * a_dim1 + 1], &c__1);
|
|
}
|
|
|
|
/* Compute the column index of the maximum column 2-norm and */
|
|
/* the maximum column 2-norm itself for the submatrix */
|
|
/* A_sub = A(1:MSUB, 1:NSUB). */
|
|
|
|
kp0 = idamax_(&nsub, &work[1], &c__1);
|
|
maxc2nrm = work[kp0];
|
|
|
|
/* ================================================================== */
|
|
/* Process preselected columns */
|
|
|
|
/* Compute the QR factorization of NSEL preselected columns (1:NSEL) */
|
|
/* in the submatrix A_sub = A(1:MSUB, 1:NSUB) and update */
|
|
/* remaining NFREE free columns (NSEL+1:NSUB). */
|
|
/* NSUB = NSEL + NFREE */
|
|
|
|
if (nsel > 0) {
|
|
|
|
/* Case (a): MSUB < NSEL. */
|
|
|
|
/* This is handled at the argument check stage in the */
|
|
/* beginning of the routine. When the number of preselected */
|
|
/* columns is larger than MSUB, hence the factorization of */
|
|
/* all NSEL columns cannot be completed. Return from the */
|
|
/* routine with the error of COL_SEL_DESEL parameter. */
|
|
|
|
/* Case (b): MSUB = NSEL. */
|
|
/* Case (c-1): MSUB > NSEL and NSEL = NSUB. */
|
|
|
|
/* For cases (b) and (c-1), there will be no residual */
|
|
/* submatrix after factorization of NSEL columns */
|
|
/* at step K = NSEL: */
|
|
/* A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB). */
|
|
|
|
/* Case (c-2): MSUB > NSEL and NSEL < NSUB. */
|
|
|
|
/* For Case (c-2) is a submatrix residual at step K=NSEL */
|
|
/* A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB) */
|
|
|
|
dgeqrf_(&msub, &nsel, &a[a_offset], lda, &tau[1], &work[1], lwork, &
|
|
iinfo);
|
|
|
|
/* Apply Q**T from the left to A(NSEL+1:MSUB, NSEL+1:NSUB) */
|
|
|
|
if (nfree > 0) {
|
|
|
|
/* This is only for case (c-2) ('L' = Left, 'T' = Transpose) */
|
|
|
|
dormqr_("L", "T", &msub, &nfree, &nsel, &a[a_offset], lda, &tau[1]
|
|
, &a[(nsel + 1) * a_dim1 + 1], lda, &work[1], lwork, &
|
|
iinfo);
|
|
}
|
|
|
|
*k += nsel;
|
|
|
|
/* End of IF(NSEL.GT.0) */
|
|
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
kfree = 0;
|
|
|
|
if (minmnfree != 0) {
|
|
|
|
/* Factorize NFREE free columns of */
|
|
/* A_free = A_sub_resid(NSEL) = A(NSEL+1:MSUB, NSEL+1:NSUB), */
|
|
/* KFREE is the number of columns that were actually factorized */
|
|
/* among NFREE columns. */
|
|
|
|
/* ================================================================== */
|
|
|
|
eps = dlamch_("Epsilon");
|
|
|
|
usetol = FALSE_;
|
|
|
|
/* Adjust ABSTOL only if nonnegative. Negative value means disabled. */
|
|
/* We need to keep negative value for later use in criterion */
|
|
/* check. */
|
|
|
|
if (*abstol >= 0.) {
|
|
safmin = dlamch_("Safe minimum");
|
|
/* Computing MAX */
|
|
d__1 = *abstol, d__2 = safmin * 2.;
|
|
*abstol = f2cmax(d__1,d__2);
|
|
usetol = TRUE_;
|
|
}
|
|
|
|
/* Adjust RELTOL only if nonnegative. Negative value means disabled. */
|
|
/* We need to keep negative value for later use in criterion */
|
|
/* check. */
|
|
|
|
if (*reltol >= 0.) {
|
|
*reltol = f2cmax(*reltol,eps);
|
|
usetol = TRUE_;
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Disable RELTOLFREE when calling DGEQP3RK for free columns */
|
|
/* factorization, since DGEQP3RK expects RELTOLFREE with respect */
|
|
/* to the residual matrix A_sub_resid(NSEL), not the whole */
|
|
/* original matrix A. We can use RELTOL criterion by passing it */
|
|
/* to ABSTOLFREE as RELTOL*MAXC2NRM. We need to make sure that */
|
|
/* the negative values of ABSTOL and RELTOL are propagated */
|
|
/* to ABSTOLFREE and RELTOLFREE, since negative values means */
|
|
/* that the criterion is disabled. */
|
|
|
|
if (usetol) {
|
|
/* Computing MAX */
|
|
d__1 = *abstol, d__2 = *reltol * maxc2nrm;
|
|
abstolfree = f2cmax(d__1,d__2);
|
|
} else {
|
|
abstolfree = -1.;
|
|
}
|
|
reltolfree = -1.;
|
|
|
|
/* Save JPIV(NSEL+1:NSUB) into WORK(NFREE+1:2*NFREE-1) */
|
|
|
|
if (nsel != 0) {
|
|
i__1 = nfree;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
iwork[nfree + j] = jpiv[nsel + j];
|
|
}
|
|
}
|
|
|
|
dgeqp3rk_(&mfree, &nfree, &c__0, kmaxfree, &abstolfree, &reltolfree, &
|
|
a[nsel + 1 + (nsel + 1) * a_dim1], lda, &kfree, &
|
|
maxc2nrmkfree, &relmaxc2nrmkfree, &jpiv[nsel + 1], &tau[nsel
|
|
+ 1], &work[1], lwork, &iwork[1], &iinfo);
|
|
|
|
/* Adjust JPIV */
|
|
|
|
if (nsel != 0) {
|
|
i__1 = nfree;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
jpiv[nsel + j] = iwork[nfree + jpiv[nsel + j]];
|
|
}
|
|
}
|
|
|
|
/* 1) Adjust the return value for the number of factorized */
|
|
/* columns K for the whole submatrix A_sub. */
|
|
/* 2) MAXC2NRMK is returned transparently without change */
|
|
/* as MAXC2NRMKFREE is returned from DGEQP3RK. */
|
|
/* 3) Adjust the return value RELMAXC2NRMK for the whole */
|
|
/* submatrix A_sub. We do not use RELMAXC2NRMKFREE */
|
|
/* returned from DGEQP3RK. */
|
|
|
|
*k += kfree;
|
|
*maxc2nrmk = maxc2nrmkfree;
|
|
*relmaxc2nrmk = *maxc2nrmk / maxc2nrm;
|
|
|
|
} else {
|
|
|
|
/* Set norms to zero */
|
|
|
|
*maxc2nrmk = 0.;
|
|
*relmaxc2nrmk = 0.;
|
|
|
|
}
|
|
|
|
/* Now, MRESID and NRESID is the number of rows and columns */
|
|
/* respectively in A_free_resid = A(K+1:MSUB,K+1:NSUB). */
|
|
|
|
mresid = mfree - kfree;
|
|
nresid = nfree - kfree;
|
|
|
|
if (f2cmin(mresid,nresid) != 0) {
|
|
*fnrmk = dlange_("F", &mresid, &nresid, &a[*k + 1 + (*k + 1) * a_dim1]
|
|
, lda, &work[1]);
|
|
} else {
|
|
*fnrmk = 0.;
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Return the matrix C. */
|
|
|
|
if (returnc && *k > 0) {
|
|
|
|
if (returnx) {
|
|
|
|
/* Copy the selected K columns of the original matrix A (that was */
|
|
/* saved into the array X) into the array C according to */
|
|
/* the pivot array JPIV. If we return X, then the matrix A is */
|
|
/* saved in the array X, and it is faster to copy into C than */
|
|
/* doing column permutation in place, as it is the ELSE case. */
|
|
|
|
i__1 = *k;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
dcopy_(m, &x[jpiv[j] * x_dim1 + 1], &c__1, &c__[j * c_dim1 +
|
|
1], &c__1);
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Swap the columns of the original matrix A copied into */
|
|
/* the array C in place. */
|
|
|
|
/* The original M-by-N matrix A was copied into the array C at */
|
|
/* the beginning of the routine, if RETURNC = .TRUE.. */
|
|
/* Apply the column permutation matrix P stored in JPIV(1:K) */
|
|
/* to the columns 1:K in the M-by-N array C in place. */
|
|
/* After column interchanges, the first K columns of C should */
|
|
/* be the same as the first K columns of A*P, i.e. */
|
|
/* (A*P)(1:M,1:K) = C(1:M,1:K). The complexity of this algorithm */
|
|
/* is f2cmin(K,N-1). */
|
|
|
|
/* Index I is the original column index in the */
|
|
/* array C before interchanges. */
|
|
/* J is the current column index of the original column I at */
|
|
/* each step of interchanges. */
|
|
|
|
/* Auxiliary array IWORK(1:N) stores the inverse P_inv(J) */
|
|
/* of the current column permutation matrix P(J) at each */
|
|
/* column interchange step J only for the array */
|
|
/* values >= J:N. */
|
|
/* C_prev = P_inv(J) * C_next. */
|
|
/* Each IWORK(I) contains JJ corresponding to I */
|
|
/* Initialize IWORK(1:N) as (1:N). */
|
|
|
|
i__1 = *n;
|
|
for (i__ = 1; i__ <= i__1; ++i__) {
|
|
iwork[i__] = i__;
|
|
}
|
|
|
|
/* Auxiliary array IWORK(N+1:2N) stores the current column */
|
|
/* permutation matrix P_(J) at each column interchange step J */
|
|
/* only for the array index >= J:N. */
|
|
/* C_prev * P_(J) = C_next. */
|
|
/* Each IWORK(N+JJ) contains I corresponding to JJ. */
|
|
/* Initialize IWORK(N+1:2*N) as (1:N). */
|
|
|
|
i__1 = *n;
|
|
for (j = 1; j <= i__1; ++j) {
|
|
iwork[*n + j] = j;
|
|
}
|
|
|
|
/* Loop over the columns J = ( 1:f2cmin( K, N-1 ) ) in C. */
|
|
|
|
/* Computing MIN */
|
|
i__2 = *k, i__3 = *n - 1;
|
|
i__1 = f2cmin(i__2,i__3);
|
|
for (j = 1; j <= i__1; ++j) {
|
|
|
|
/* IP is the original pivot column, i.e. is the original */
|
|
/* column that should be placed in the current column index */
|
|
/* J in the array C. */
|
|
|
|
ip = jpiv[j];
|
|
|
|
/* I is the original column that is */
|
|
/* currently in the column index J in the array C after */
|
|
/* previous column interchanges. */
|
|
|
|
i__ = iwork[*n + j];
|
|
|
|
if (i__ != ip) {
|
|
|
|
/* JP is the current index of the original pivot */
|
|
/* column IP in the array C after previous column */
|
|
/* interchanges. */
|
|
|
|
jp = iwork[ip];
|
|
/* Swap the original pivot column IP = JPIV( J ), */
|
|
/* at the current pivot index JP = IWORK( IP ) into */
|
|
/* index J. */
|
|
|
|
dswap_(m, &c__[j * c_dim1 + 1], &c__1, &c__[jp * c_dim1 +
|
|
1], &c__1);
|
|
|
|
/* Update the array IWORK(1:N) for the original column */
|
|
/* I that was swapped with IP. */
|
|
|
|
iwork[i__] = iwork[ip];
|
|
|
|
/* Update the array IWORK(N+1:2*N) for the current column */
|
|
/* index JP that was swapped with the current column */
|
|
/* index J. */
|
|
|
|
iwork[*n + jp] = iwork[*n + j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* End of ELSE( RETURNX ) */
|
|
|
|
}
|
|
|
|
/* End of IF( RETURNC .AND. K.GT.0 ) */
|
|
|
|
}
|
|
|
|
/* ================================================================== */
|
|
|
|
/* Return the matrix X. */
|
|
|
|
if (returnx && *k > 0) {
|
|
|
|
/* We need to use C and A to compute X = pseudoinv(C) * A, as */
|
|
/* the linear least squares solution to the overdetermined system */
|
|
/* C*X = A. We use LLS routine that uses the QR factorization. For */
|
|
/* that purpose, we store the matrix C into the array QRC. */
|
|
/* The matrix A was copied into the array X at the beginning */
|
|
/* of the routine. */
|
|
|
|
dlacpy_("F", m, k, &c__[c_offset], ldc, &qrc[qrc_offset], ldqrc);
|
|
|
|
dgels_("N", m, k, n, &qrc[qrc_offset], ldqrc, &x[x_offset], ldx, &
|
|
work[1], lwork, &iinfo);
|
|
*info = iinfo;
|
|
|
|
}
|
|
|
|
work[1] = (doublereal) lwkopt;
|
|
iwork[1] = liwkopt;
|
|
|
|
/* End of DGECXX */
|
|
|
|
return 0;
|
|
} /* dgecxx_ */
|
|
|