summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/matrix/lapack
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/matrix/lapack')
-rw-r--r--ml/dlib/dlib/matrix/lapack/fortran_id.h62
-rw-r--r--ml/dlib/dlib/matrix/lapack/gees.h264
-rw-r--r--ml/dlib/dlib/matrix/lapack/geev.h234
-rw-r--r--ml/dlib/dlib/matrix/lapack/geqrf.h168
-rw-r--r--ml/dlib/dlib/matrix/lapack/gesdd.h364
-rw-r--r--ml/dlib/dlib/matrix/lapack/gesvd.h323
-rw-r--r--ml/dlib/dlib/matrix/lapack/getrf.h132
-rw-r--r--ml/dlib/dlib/matrix/lapack/ormqr.h224
-rw-r--r--ml/dlib/dlib/matrix/lapack/pbtrf.h178
-rw-r--r--ml/dlib/dlib/matrix/lapack/potrf.h174
-rw-r--r--ml/dlib/dlib/matrix/lapack/syev.h218
-rw-r--r--ml/dlib/dlib/matrix/lapack/syevr.h445
12 files changed, 2786 insertions, 0 deletions
diff --git a/ml/dlib/dlib/matrix/lapack/fortran_id.h b/ml/dlib/dlib/matrix/lapack/fortran_id.h
new file mode 100644
index 000000000..8027ea34f
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/fortran_id.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H
+#define DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H
+
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+// FORTRAN BINDING STUFF FROM BOOST
+// ----------------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------------------
+
+// Permission to copy, use, modify, sell and
+// distribute this software is granted provided this copyright notice appears
+// in all copies. This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+// Copyright (C) 2002, 2003 Si-Lab b.v.b.a., Toon Knapen and Kresimir Fresl
+
+
+// First we need to know what the conventions for linking
+// C with Fortran is on this platform/toolset
+#if defined(LAPACK_FORCE_UNDERSCORE)
+#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE
+#elif defined(LAPACK_FORCE_NOUNDERSCORE)
+#define DLIB_BIND_FORTRAN_LOWERCASE
+#elif defined(__GNUC__) || defined(__ICC) || defined(__sgi) || defined(__COMO__) || defined(__KCC)
+#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE
+#elif defined(__IBMCPP__) || defined(_MSC_VER) || defined(__BORLANDC__)
+#define DLIB_BIND_FORTRAN_LOWERCASE
+#else
+#error do not know how to link with fortran for the given platform
+#endif
+
+// Next we define macros to convert our symbols to
+// the current convention
+#if defined(DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE)
+#define DLIB_FORTRAN_ID( id ) id##_
+#elif defined(DLIB_BIND_FORTRAN_LOWERCASE)
+#define DLIB_FORTRAN_ID( id ) id
+#else
+#error do not know how to bind to fortran calling convention
+#endif
+
+
+
+namespace dlib
+{
+ namespace lapack
+ {
+ // stuff from f2c used to define what exactly is an integer in fortran
+#if (defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)) && !defined(MATLAB_MEX_FILE)
+ typedef int integer;
+ typedef unsigned int uinteger;
+#else
+ typedef long int integer;
+ typedef unsigned long int uinteger;
+#endif
+
+ }
+}
+
+#endif // DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H
+
diff --git a/ml/dlib/dlib/matrix/lapack/gees.h b/ml/dlib/dlib/matrix/lapack/gees.h
new file mode 100644
index 000000000..a8ee63ff1
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/gees.h
@@ -0,0 +1,264 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_ES_Hh_
+#define DLIB_LAPACk_ES_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+#if defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)
+ typedef int logical;
+#else
+ typedef long int logical;
+#endif
+ typedef logical (*L_fp)(...);
+
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgees) (char *jobvs, char *sort, L_fp select, integer *n,
+ double *a, integer *lda, integer *sdim, double *wr,
+ double *wi, double *vs, integer *ldvs, double *work,
+ integer *lwork, logical *bwork, integer *info);
+
+ void DLIB_FORTRAN_ID(sgees) (char *jobvs, char *sort, L_fp select, integer *n,
+ float *a, integer *lda, integer *sdim, float *wr,
+ float *wi, float *vs, integer *ldvs, float *work,
+ integer *lwork, logical *bwork, integer *info);
+
+ }
+
+ inline int gees (char jobvs, integer n,
+ double *a, integer lda, double *wr,
+ double *wi, double *vs, integer ldvs, double *work,
+ integer lwork)
+ {
+ // No sorting allowed
+ integer info = 0;
+ char sort = 'N';
+ L_fp fnil = 0;
+ logical bwork = 0;
+ integer sdim = 0;
+ DLIB_FORTRAN_ID(dgees)(&jobvs, &sort, fnil, &n,
+ a, &lda, &sdim, wr,
+ wi, vs, &ldvs, work,
+ &lwork, &bwork, &info);
+ return info;
+ }
+
+
+ inline int gees (char jobvs, integer n,
+ float *a, integer lda, float *wr,
+ float *wi, float *vs, integer ldvs, float *work,
+ integer lwork)
+ {
+ // No sorting allowed
+ integer info = 0;
+ char sort = 'N';
+ L_fp fnil = 0;
+ logical bwork = 0;
+ integer sdim = 0;
+ DLIB_FORTRAN_ID(sgees)(&jobvs, &sort, fnil, &n,
+ a, &lda, &sdim, wr,
+ wi, vs, &ldvs, work,
+ &lwork, &bwork, &info);
+ return info;
+ }
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK driver routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+/* .. Function Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGEES computes for an N-by-N real nonsymmetric matrix A, the */
+/* eigenvalues, the real Schur form T, and, optionally, the matrix of */
+/* Schur vectors Z. This gives the Schur factorization A = Z*T*(Z**T). */
+
+/* Optionally, it also orders the eigenvalues on the diagonal of the */
+/* real Schur form so that selected eigenvalues are at the top left. */
+/* The leading columns of Z then form an orthonormal basis for the */
+/* invariant subspace corresponding to the selected eigenvalues. */
+
+/* A matrix is in real Schur form if it is upper quasi-triangular with */
+/* 1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the */
+/* form */
+/* [ a b ] */
+/* [ c a ] */
+
+/* where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). */
+
+/* Arguments */
+/* ========= */
+
+/* JOBVS (input) CHARACTER*1 */
+/* = 'N': Schur vectors are not computed; */
+/* = 'V': Schur vectors are computed. */
+
+/* SORT (input) CHARACTER*1 */
+/* Specifies whether or not to order the eigenvalues on the */
+/* diagonal of the Schur form. */
+/* = 'N': Eigenvalues are not ordered; */
+/* = 'S': Eigenvalues are ordered (see SELECT). */
+
+/* SELECT (external procedure) LOGICAL FUNCTION of two DOUBLE PRECISION arguments */
+/* SELECT must be declared EXTERNAL in the calling subroutine. */
+/* If SORT = 'S', SELECT is used to select eigenvalues to sort */
+/* to the top left of the Schur form. */
+/* If SORT = 'N', SELECT is not referenced. */
+/* An eigenvalue WR(j)+sqrt(-1)*WI(j) is selected if */
+/* SELECT(WR(j),WI(j)) is true; i.e., if either one of a complex */
+/* conjugate pair of eigenvalues is selected, then both complex */
+/* eigenvalues are selected. */
+/* Note that a selected complex eigenvalue may no longer */
+/* satisfy SELECT(WR(j),WI(j)) = .TRUE. after ordering, since */
+/* ordering may change the value of complex eigenvalues */
+/* (especially if the eigenvalue is ill-conditioned); in this */
+/* case INFO is set to N+2 (see INFO below). */
+
+/* N (input) INTEGER */
+/* The order of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the N-by-N matrix A. */
+/* On exit, A has been overwritten by its real Schur form T. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,N). */
+
+/* SDIM (output) INTEGER */
+/* If SORT = 'N', SDIM = 0. */
+/* If SORT = 'S', SDIM = number of eigenvalues (after sorting) */
+/* for which SELECT is true. (Complex conjugate */
+/* pairs for which SELECT is true for either */
+/* eigenvalue count as 2.) */
+
+/* WR (output) DOUBLE PRECISION array, dimension (N) */
+/* WI (output) DOUBLE PRECISION array, dimension (N) */
+/* WR and WI contain the real and imaginary parts, */
+/* respectively, of the computed eigenvalues in the same order */
+/* that they appear on the diagonal of the output Schur form T. */
+/* Complex conjugate pairs of eigenvalues will appear */
+/* consecutively with the eigenvalue having the positive */
+/* imaginary part first. */
+
+/* VS (output) DOUBLE PRECISION array, dimension (LDVS,N) */
+/* If JOBVS = 'V', VS contains the orthogonal matrix Z of Schur */
+/* vectors. */
+/* If JOBVS = 'N', VS is not referenced. */
+
+/* LDVS (input) INTEGER */
+/* The leading dimension of the array VS. LDVS >= 1; if */
+/* JOBVS = 'V', LDVS >= N. */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) contains the optimal LWORK. */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. LWORK >= max(1,3*N). */
+/* For good performance, LWORK must generally be larger. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* BWORK (workspace) LOGICAL array, dimension (N) */
+/* Not referenced if SORT = 'N'. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value. */
+/* > 0: if INFO = i, and i is */
+/* <= N: the QR algorithm failed to compute all the */
+/* eigenvalues; elements 1:ILO-1 and i+1:N of WR and WI */
+/* contain those eigenvalues which have converged; if */
+/* JOBVS = 'V', VS contains the matrix which reduces A */
+/* to its partially converged Schur form. */
+/* = N+1: the eigenvalues could not be reordered because some */
+/* eigenvalues were too close to separate (the problem */
+/* is very ill-conditioned); */
+/* = N+2: after reordering, roundoff changed values of some */
+/* complex eigenvalues so that leading eigenvalues in */
+/* the Schur form no longer satisfy SELECT=.TRUE. This */
+/* could also be caused by underflow due to scaling. */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM,
+ typename layout
+ >
+ int gees (
+ const char jobz,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,layout>& wr,
+ matrix<T,NR3,NC3,MM,layout>& wi,
+ matrix<T,NR4,NC4,MM,column_major_layout>& vs
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ const long n = a.nr();
+
+ wr.set_size(n,1);
+ wi.set_size(n,1);
+
+ if (jobz == 'V')
+ vs.set_size(n,n);
+ else
+ vs.set_size(NR4?NR4:1, NC4?NC4:1);
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::gees(jobz, n,
+ &a(0,0), a.nr(), &wr(0,0),
+ &wi(0,0), &vs(0,0), vs.nr(), &work_size,
+ -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual decomposition
+ info = binding::gees(jobz, n,
+ &a(0,0), a.nr(), &wr(0,0),
+ &wi(0,0), &vs(0,0), vs.nr(), &work(0,0),
+ work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_ES_Hh_
+
diff --git a/ml/dlib/dlib/matrix/lapack/geev.h b/ml/dlib/dlib/matrix/lapack/geev.h
new file mode 100644
index 000000000..d8fdc4af5
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/geev.h
@@ -0,0 +1,234 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_GEEV_Hh_
+#define DLIB_LAPACk_GEEV_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgeev) (char *jobvl, char *jobvr, integer *n, double * a,
+ integer *lda, double *wr, double *wi, double *vl,
+ integer *ldvl, double *vr, integer *ldvr, double *work,
+ integer *lwork, integer *info);
+
+ void DLIB_FORTRAN_ID(sgeev) (char *jobvl, char *jobvr, integer *n, float * a,
+ integer *lda, float *wr, float *wi, float *vl,
+ integer *ldvl, float *vr, integer *ldvr, float *work,
+ integer *lwork, integer *info);
+
+ }
+
+ inline int geev (char jobvl, char jobvr, integer n, double *a,
+ integer lda, double *wr, double *wi, double *vl,
+ integer ldvl, double *vr, integer ldvr, double *work,
+ integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dgeev)(&jobvl, &jobvr, &n, a,
+ &lda, wr, wi, vl,
+ &ldvl, vr, &ldvr, work,
+ &lwork, &info);
+ return info;
+ }
+
+ inline int geev (char jobvl, char jobvr, integer n, float *a,
+ integer lda, float *wr, float *wi, float *vl,
+ integer ldvl, float *vr, integer ldvr, float *work,
+ integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sgeev)(&jobvl, &jobvr, &n, a,
+ &lda, wr, wi, vl,
+ &ldvl, vr, &ldvr, work,
+ &lwork, &info);
+ return info;
+ }
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK driver routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGEEV computes for an N-by-N real nonsymmetric matrix A, the */
+/* eigenvalues and, optionally, the left and/or right eigenvectors. */
+
+/* The right eigenvector v(j) of A satisfies */
+/* A * v(j) = lambda(j) * v(j) */
+/* where lambda(j) is its eigenvalue. */
+/* The left eigenvector u(j) of A satisfies */
+/* u(j)**H * A = lambda(j) * u(j)**H */
+/* where u(j)**H denotes the conjugate transpose of u(j). */
+
+/* The computed eigenvectors are normalized to have Euclidean norm */
+/* equal to 1 and largest component real. */
+
+/* Arguments */
+/* ========= */
+
+/* JOBVL (input) CHARACTER*1 */
+/* = 'N': left eigenvectors of A are not computed; */
+/* = 'V': left eigenvectors of A are computed. */
+
+/* JOBVR (input) CHARACTER*1 */
+/* = 'N': right eigenvectors of A are not computed; */
+/* = 'V': right eigenvectors of A are computed. */
+
+/* N (input) INTEGER */
+/* The order of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the N-by-N matrix A. */
+/* On exit, A has been overwritten. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,N). */
+
+/* WR (output) DOUBLE PRECISION array, dimension (N) */
+/* WI (output) DOUBLE PRECISION array, dimension (N) */
+/* WR and WI contain the real and imaginary parts, */
+/* respectively, of the computed eigenvalues. Complex */
+/* conjugate pairs of eigenvalues appear consecutively */
+/* with the eigenvalue having the positive imaginary part */
+/* first. */
+
+/* VL (output) DOUBLE PRECISION array, dimension (LDVL,N) */
+/* If JOBVL = 'V', the left eigenvectors u(j) are stored one */
+/* after another in the columns of VL, in the same order */
+/* as their eigenvalues. */
+/* If JOBVL = 'N', VL is not referenced. */
+/* If the j-th eigenvalue is real, then u(j) = VL(:,j), */
+/* the j-th column of VL. */
+/* If the j-th and (j+1)-st eigenvalues form a complex */
+/* conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and */
+/* u(j+1) = VL(:,j) - i*VL(:,j+1). */
+
+/* LDVL (input) INTEGER */
+/* The leading dimension of the array VL. LDVL >= 1; if */
+/* JOBVL = 'V', LDVL >= N. */
+
+/* VR (output) DOUBLE PRECISION array, dimension (LDVR,N) */
+/* If JOBVR = 'V', the right eigenvectors v(j) are stored one */
+/* after another in the columns of VR, in the same order */
+/* as their eigenvalues. */
+/* If JOBVR = 'N', VR is not referenced. */
+/* If the j-th eigenvalue is real, then v(j) = VR(:,j), */
+/* the j-th column of VR. */
+/* If the j-th and (j+1)-st eigenvalues form a complex */
+/* conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and */
+/* v(j+1) = VR(:,j) - i*VR(:,j+1). */
+
+/* LDVR (input) INTEGER */
+/* The leading dimension of the array VR. LDVR >= 1; if */
+/* JOBVR = 'V', LDVR >= N. */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. LWORK >= max(1,3*N), and */
+/* if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N. For good */
+/* performance, LWORK must generally be larger. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value. */
+/* > 0: if INFO = i, the QR algorithm failed to compute all the */
+/* eigenvalues, and no eigenvectors have been computed; */
+/* elements i+1:N of WR and WI contain eigenvalues which */
+/* have converged. */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4, long NR5,
+ long NC1, long NC2, long NC3, long NC4, long NC5,
+ typename MM,
+ typename layout
+ >
+ int geev (
+ const char jobvl,
+ const char jobvr,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,layout>& wr,
+ matrix<T,NR3,NC3,MM,layout>& wi,
+ matrix<T,NR4,NC4,MM,column_major_layout>& vl,
+ matrix<T,NR5,NC5,MM,column_major_layout>& vr
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ const long n = a.nr();
+
+ wr.set_size(n,1);
+ wi.set_size(n,1);
+
+ if (jobvl == 'V')
+ vl.set_size(n,n);
+ else
+ vl.set_size(NR4?NR4:1, NC4?NC4:1);
+
+ if (jobvr == 'V')
+ vr.set_size(n,n);
+ else
+ vr.set_size(NR5?NR5:1, NC5?NC5:1);
+
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::geev(jobvl, jobvr, n, &a(0,0),
+ a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),
+ vl.nr(), &vr(0,0), vr.nr(), &work_size,
+ -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual decomposition
+ info = binding::geev(jobvl, jobvr, n, &a(0,0),
+ a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),
+ vl.nr(), &vr(0,0), vr.nr(), &work(0,0),
+ work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_GEEV_Hh_
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/geqrf.h b/ml/dlib/dlib/matrix/lapack/geqrf.h
new file mode 100644
index 000000000..c1f8fc050
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/geqrf.h
@@ -0,0 +1,168 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_GEQRF_Hh_
+#define DLIB_LAPACk_GEQRF_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgeqrf) (integer *m, integer *n, double *a, integer *
+ lda, double *tau, double *work, integer *lwork,
+ integer *info);
+
+ void DLIB_FORTRAN_ID(sgeqrf) (integer *m, integer *n, float *a, integer *
+ lda, float *tau, float *work, integer *lwork,
+ integer *info);
+ }
+
+ inline int geqrf (integer m, integer n, double *a, integer lda,
+ double *tau, double *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dgeqrf)(&m, &n, a, &lda,
+ tau, work, &lwork, &info);
+ return info;
+ }
+
+ inline int geqrf (integer m, integer n, float *a, integer lda,
+ float *tau, float *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sgeqrf)(&m, &n, a, &lda,
+ tau, work, &lwork, &info);
+ return info;
+ }
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGEQRF computes a QR factorization of a real M-by-N matrix A: */
+/* A = Q * R. */
+
+/* Arguments */
+/* ========= */
+
+/* M (input) INTEGER */
+/* The number of rows of the matrix A. M >= 0. */
+
+/* N (input) INTEGER */
+/* The number of columns of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the M-by-N matrix A. */
+/* On exit, the elements on and above the diagonal of the array */
+/* contain the min(M,N)-by-N upper trapezoidal matrix R (R is */
+/* upper triangular if m >= n); the elements below the diagonal, */
+/* with the array TAU, represent the orthogonal matrix Q as a */
+/* product of min(m,n) elementary reflectors (see Further */
+/* Details). */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,M). */
+
+/* TAU (output) DOUBLE PRECISION array, dimension (min(M,N)) */
+/* The scalar factors of the elementary reflectors (see Further */
+/* Details). */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. LWORK >= max(1,N). */
+/* For optimum performance LWORK >= N*NB, where NB is */
+/* the optimal blocksize. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value */
+
+/* Further Details */
+/* =============== */
+
+/* The matrix Q is represented as a product of elementary reflectors */
+
+/* Q = H(1) H(2) . . . H(k), where k = min(m,n). */
+
+/* Each H(i) has the form */
+
+/* H(i) = I - tau * v * v' */
+
+/* where tau is a real scalar, and v is a real vector with */
+/* v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), */
+/* and tau in TAU(i). */
+
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2,
+ long NC1, long NC2,
+ typename MM
+ >
+ int geqrf (
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,column_major_layout>& tau
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ tau.set_size(std::min(a.nr(), a.nc()), 1);
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),
+ &tau(0,0), &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual decomposition
+ info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),
+ &tau(0,0), &work(0,0), work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_GEQRF_Hh_
+
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/gesdd.h b/ml/dlib/dlib/matrix/lapack/gesdd.h
new file mode 100644
index 000000000..e6b4d26e1
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/gesdd.h
@@ -0,0 +1,364 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_SDD_Hh_
+#define DLIB_LAPACk_SDD_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgesdd) (char const* jobz,
+ const integer* m, const integer* n, double* a, const integer* lda,
+ double* s, double* u, const integer* ldu,
+ double* vt, const integer* ldvt,
+ double* work, const integer* lwork, integer* iwork, integer* info);
+
+ void DLIB_FORTRAN_ID(sgesdd) (char const* jobz,
+ const integer* m, const integer* n, float* a, const integer* lda,
+ float* s, float* u, const integer* ldu,
+ float* vt, const integer* ldvt,
+ float* work, const integer* lwork, integer* iwork, integer* info);
+
+ }
+
+ inline integer gesdd (const char jobz,
+ const integer m, const integer n, double* a, const integer lda,
+ double* s, double* u, const integer ldu,
+ double* vt, const integer ldvt,
+ double* work, const integer lwork, integer* iwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);
+ return info;
+ }
+
+ inline integer gesdd (const char jobz,
+ const integer m, const integer n, float* a, const integer lda,
+ float* s, float* u, const integer ldu,
+ float* vt, const integer ldvt,
+ float* work, const integer lwork, integer* iwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);
+ return info;
+ }
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK driver routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGESDD computes the singular value decomposition (SVD) of a real */
+/* M-by-N matrix A, optionally computing the left and right singular */
+/* vectors. If singular vectors are desired, it uses a */
+/* divide-and-conquer algorithm. */
+
+/* The SVD is written */
+
+/* A = U * SIGMA * transpose(V) */
+
+/* where SIGMA is an M-by-N matrix which is zero except for its */
+/* min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */
+/* V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA */
+/* are the singular values of A; they are real and non-negative, and */
+/* are returned in descending order. The first min(m,n) columns of */
+/* U and V are the left and right singular vectors of A. */
+
+/* Note that the routine returns VT = V**T, not V. */
+
+/* The divide and conquer algorithm makes very mild assumptions about */
+/* floating point arithmetic. It will work on machines with a guard */
+/* digit in add/subtract, or on those binary machines without guard */
+/* digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */
+/* Cray-2. It could conceivably fail on hexadecimal or decimal machines */
+/* without guard digits, but we know of none. */
+
+/* Arguments */
+/* ========= */
+
+/* JOBZ (input) CHARACTER*1 */
+/* Specifies options for computing all or part of the matrix U: */
+/* = 'A': all M columns of U and all N rows of V**T are */
+/* returned in the arrays U and VT; */
+/* = 'S': the first min(M,N) columns of U and the first */
+/* min(M,N) rows of V**T are returned in the arrays U */
+/* and VT; */
+/* = 'O': If M >= N, the first N columns of U are overwritten */
+/* on the array A and all rows of V**T are returned in */
+/* the array VT; */
+/* otherwise, all columns of U are returned in the */
+/* array U and the first M rows of V**T are overwritten */
+/* in the array A; */
+/* = 'N': no columns of U or rows of V**T are computed. */
+
+/* M (input) INTEGER */
+/* The number of rows of the input matrix A. M >= 0. */
+
+/* N (input) INTEGER */
+/* The number of columns of the input matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the M-by-N matrix A. */
+/* On exit, */
+/* if JOBZ = 'O', A is overwritten with the first N columns */
+/* of U (the left singular vectors, stored */
+/* columnwise) if M >= N; */
+/* A is overwritten with the first M rows */
+/* of V**T (the right singular vectors, stored */
+/* rowwise) otherwise. */
+/* if JOBZ .ne. 'O', the contents of A are destroyed. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,M). */
+
+/* S (output) DOUBLE PRECISION array, dimension (min(M,N)) */
+/* The singular values of A, sorted so that S(i) >= S(i+1). */
+
+/* U (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */
+/* UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; */
+/* UCOL = min(M,N) if JOBZ = 'S'. */
+/* If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M */
+/* orthogonal matrix U; */
+/* if JOBZ = 'S', U contains the first min(M,N) columns of U */
+/* (the left singular vectors, stored columnwise); */
+/* if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. */
+
+/* LDU (input) INTEGER */
+/* The leading dimension of the array U. LDU >= 1; if */
+/* JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. */
+
+/* VT (output) DOUBLE PRECISION array, dimension (LDVT,N) */
+/* If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the */
+/* N-by-N orthogonal matrix V**T; */
+/* if JOBZ = 'S', VT contains the first min(M,N) rows of */
+/* V**T (the right singular vectors, stored rowwise); */
+/* if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. */
+
+/* LDVT (input) INTEGER */
+/* The leading dimension of the array VT. LDVT >= 1; if */
+/* JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; */
+/* if JOBZ = 'S', LDVT >= min(M,N). */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. LWORK >= 1. */
+/* If JOBZ = 'N', */
+/* LWORK >= 3*min(M,N) + max(max(M,N),7*min(M,N)). */
+/* If JOBZ = 'O', */
+/* LWORK >= 3*min(M,N)*min(M,N) + */
+/* max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)). */
+/* If JOBZ = 'S' or 'A' */
+/* LWORK >= 3*min(M,N)*min(M,N) + */
+/* max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)). */
+/* For good performance, LWORK should generally be larger. */
+/* If LWORK = -1 but other input arguments are legal, WORK(1) */
+/* returns the optimal LWORK. */
+
+/* IWORK (workspace) INTEGER array, dimension (8*min(M,N)) */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit. */
+/* < 0: if INFO = -i, the i-th argument had an illegal value. */
+/* > 0: DBDSDC did not converge, updating process failed. */
+
+/* Further Details */
+/* =============== */
+
+/* Based on contributions by */
+/* Ming Gu and Huan Ren, Computer Science Division, University of */
+/* California at Berkeley, USA */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int gesdd (
+ const char jobz,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,column_major_layout>& s,
+ matrix<T,NR3,NC3,MM,column_major_layout>& u,
+ matrix<T,NR4,NC4,MM,column_major_layout>& vt
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+ matrix<integer,0,1,MM,column_major_layout> iwork;
+
+ const long m = a.nr();
+ const long n = a.nc();
+ s.set_size(std::min(m,n), 1);
+
+ // make sure the iwork memory block is big enough
+ if (iwork.size() < 8*std::min(m,n))
+ iwork.set_size(8*std::min(m,n), 1);
+
+ if (jobz == 'A')
+ {
+ u.set_size(m,m);
+ vt.set_size(n,n);
+ }
+ else if (jobz == 'S')
+ {
+ u.set_size(m, std::min(m,n));
+ vt.set_size(std::min(m,n), n);
+ }
+ else if (jobz == 'O')
+ {
+ DLIB_CASSERT(false, "jobz == 'O' not supported");
+ }
+ else
+ {
+ u.set_size(NR3?NR3:1, NC3?NC3:1);
+ vt.set_size(NR4?NR4:1, NC4?NC4:1);
+ }
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),
+ &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
+ &work_size, -1, &iwork(0,0));
+
+ if (info != 0)
+ return info;
+
+ // There is a bug in an older version of LAPACK in Debian etch
+ // that causes the gesdd to return the wrong value for work_size
+ // when jobz == 'N'. So verify the value of work_size.
+ if (jobz == 'N')
+ {
+ using std::min;
+ using std::max;
+ const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));
+ if (work_size < min_work_size)
+ work_size = min_work_size;
+ }
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual SVD
+ info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),
+ &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
+ &work(0,0), work.size(), &iwork(0,0));
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int gesdd (
+ const char jobz,
+ matrix<T,NR1,NC1,MM,row_major_layout>& a,
+ matrix<T,NR2,NC2,MM,row_major_layout>& s,
+ matrix<T,NR3,NC3,MM,row_major_layout>& u_,
+ matrix<T,NR4,NC4,MM,row_major_layout>& vt_
+ )
+ {
+ matrix<T,0,1,MM,row_major_layout> work;
+ matrix<integer,0,1,MM,row_major_layout> iwork;
+
+ // Row major order matrices are transposed from LAPACK's point of view.
+ matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;
+ matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;
+
+
+ const long m = a.nc();
+ const long n = a.nr();
+ s.set_size(std::min(m,n), 1);
+
+ // make sure the iwork memory block is big enough
+ if (iwork.size() < 8*std::min(m,n))
+ iwork.set_size(8*std::min(m,n), 1);
+
+ if (jobz == 'A')
+ {
+ u.set_size(m,m);
+ vt.set_size(n,n);
+ }
+ else if (jobz == 'S')
+ {
+ u.set_size(std::min(m,n), m);
+ vt.set_size(n, std::min(m,n));
+ }
+ else if (jobz == 'O')
+ {
+ DLIB_CASSERT(false, "jobz == 'O' not supported");
+ }
+ else
+ {
+ u.set_size(NR4?NR4:1, NC4?NC4:1);
+ vt.set_size(NR3?NR3:1, NC3?NC3:1);
+ }
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),
+ &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
+ &work_size, -1, &iwork(0,0));
+
+ if (info != 0)
+ return info;
+
+ // There is a bug in an older version of LAPACK in Debian etch
+ // that causes the gesdd to return the wrong value for work_size
+ // when jobz == 'N'. So verify the value of work_size.
+ if (jobz == 'N')
+ {
+ using std::min;
+ using std::max;
+ const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));
+ if (work_size < min_work_size)
+ work_size = min_work_size;
+ }
+
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual SVD
+ info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),
+ &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
+ &work(0,0), work.size(), &iwork(0,0));
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_SDD_Hh_
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/gesvd.h b/ml/dlib/dlib/matrix/lapack/gesvd.h
new file mode 100644
index 000000000..e00654db6
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/gesvd.h
@@ -0,0 +1,323 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_SVD_Hh_
+#define DLIB_LAPACk_SVD_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgesvd) (const char* jobu, const char* jobvt,
+ const integer* m, const integer* n, double* a, const integer* lda,
+ double* s, double* u, const integer* ldu,
+ double* vt, const integer* ldvt,
+ double* work, const integer* lwork, integer* info);
+
+ void DLIB_FORTRAN_ID(sgesvd) (const char* jobu, const char* jobvt,
+ const integer* m, const integer* n, float* a, const integer* lda,
+ float* s, float* u, const integer* ldu,
+ float* vt, const integer* ldvt,
+ float* work, const integer* lwork, integer* info);
+
+ }
+
+ inline integer gesvd (const char jobu, const char jobvt,
+ const integer m, const integer n, double* a, const integer lda,
+ double* s, double* u, const integer ldu,
+ double* vt, const integer ldvt,
+ double* work, const integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);
+ return info;
+ }
+
+ inline integer gesvd (const char jobu, const char jobvt,
+ const integer m, const integer n, float* a, const integer lda,
+ float* s, float* u, const integer ldu,
+ float* vt, const integer ldvt,
+ float* work, const integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);
+ return info;
+ }
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK driver routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGESVD computes the singular value decomposition (SVD) of a real */
+/* M-by-N matrix A, optionally computing the left and/or right singular */
+/* vectors. The SVD is written */
+
+/* A = U * SIGMA * transpose(V) */
+
+/* where SIGMA is an M-by-N matrix which is zero except for its */
+/* min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */
+/* V is an N-by-N orthogonal matrix. The diagonal elements of SIGMA */
+/* are the singular values of A; they are real and non-negative, and */
+/* are returned in descending order. The first min(m,n) columns of */
+/* U and V are the left and right singular vectors of A. */
+
+/* Note that the routine returns V**T, not V. */
+
+/* Arguments */
+/* ========= */
+
+/* JOBU (input) CHARACTER*1 */
+/* Specifies options for computing all or part of the matrix U: */
+/* = 'A': all M columns of U are returned in array U: */
+/* = 'S': the first min(m,n) columns of U (the left singular */
+/* vectors) are returned in the array U; */
+/* = 'O': the first min(m,n) columns of U (the left singular */
+/* vectors) are overwritten on the array A; */
+/* = 'N': no columns of U (no left singular vectors) are */
+/* computed. */
+
+/* JOBVT (input) CHARACTER*1 */
+/* Specifies options for computing all or part of the matrix */
+/* V**T: */
+/* = 'A': all N rows of V**T are returned in the array VT; */
+/* = 'S': the first min(m,n) rows of V**T (the right singular */
+/* vectors) are returned in the array VT; */
+/* = 'O': the first min(m,n) rows of V**T (the right singular */
+/* vectors) are overwritten on the array A; */
+/* = 'N': no rows of V**T (no right singular vectors) are */
+/* computed. */
+
+/* JOBVT and JOBU cannot both be 'O'. */
+
+/* M (input) INTEGER */
+/* The number of rows of the input matrix A. M >= 0. */
+
+/* N (input) INTEGER */
+/* The number of columns of the input matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the M-by-N matrix A. */
+/* On exit, */
+/* if JOBU = 'O', A is overwritten with the first min(m,n) */
+/* columns of U (the left singular vectors, */
+/* stored columnwise); */
+/* if JOBVT = 'O', A is overwritten with the first min(m,n) */
+/* rows of V**T (the right singular vectors, */
+/* stored rowwise); */
+/* if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A */
+/* are destroyed. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,M). */
+
+/* S (output) DOUBLE PRECISION array, dimension (min(M,N)) */
+/* The singular values of A, sorted so that S(i) >= S(i+1). */
+
+/* U (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */
+/* (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'. */
+/* If JOBU = 'A', U contains the M-by-M orthogonal matrix U; */
+/* if JOBU = 'S', U contains the first min(m,n) columns of U */
+/* (the left singular vectors, stored columnwise); */
+/* if JOBU = 'N' or 'O', U is not referenced. */
+
+/* LDU (input) INTEGER */
+/* The leading dimension of the array U. LDU >= 1; if */
+/* JOBU = 'S' or 'A', LDU >= M. */
+
+/* VT (output) DOUBLE PRECISION array, dimension (LDVT,N) */
+/* If JOBVT = 'A', VT contains the N-by-N orthogonal matrix */
+/* V**T; */
+/* if JOBVT = 'S', VT contains the first min(m,n) rows of */
+/* V**T (the right singular vectors, stored rowwise); */
+/* if JOBVT = 'N' or 'O', VT is not referenced. */
+
+/* LDVT (input) INTEGER */
+/* The leading dimension of the array VT. LDVT >= 1; if */
+/* JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N). */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */
+/* if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged */
+/* superdiagonal elements of an upper bidiagonal matrix B */
+/* whose diagonal is in S (not necessarily sorted). B */
+/* satisfies A = U * B * VT, so it has the same singular values */
+/* as A, and singular vectors related by U and VT. */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. */
+/* LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)). */
+/* For good performance, LWORK should generally be larger. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit. */
+/* < 0: if INFO = -i, the i-th argument had an illegal value. */
+/* > 0: if DBDSQR did not converge, INFO specifies how many */
+/* superdiagonals of an intermediate bidiagonal form B */
+/* did not converge to zero. See the description of WORK */
+/* above for details. */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int gesvd (
+ const char jobu,
+ const char jobvt,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,column_major_layout>& s,
+ matrix<T,NR3,NC3,MM,column_major_layout>& u,
+ matrix<T,NR4,NC4,MM,column_major_layout>& vt
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ const long m = a.nr();
+ const long n = a.nc();
+ s.set_size(std::min(m,n), 1);
+
+ if (jobu == 'A')
+ u.set_size(m,m);
+ else if (jobu == 'S')
+ u.set_size(m, std::min(m,n));
+ else
+ u.set_size(NR3?NR3:1, NC3?NC3:1);
+
+ if (jobvt == 'A')
+ vt.set_size(n,n);
+ else if (jobvt == 'S')
+ vt.set_size(std::min(m,n), n);
+ else
+ vt.set_size(NR4?NR4:1, NC4?NC4:1);
+
+
+ if (jobu == 'O' || jobvt == 'O')
+ {
+ DLIB_CASSERT(false, "job == 'O' not supported");
+ }
+
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),
+ &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
+ &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual SVD
+ info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),
+ &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),
+ &work(0,0), work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int gesvd (
+ char jobu,
+ char jobvt,
+ matrix<T,NR1,NC1,MM,row_major_layout>& a,
+ matrix<T,NR2,NC2,MM,row_major_layout>& s,
+ matrix<T,NR3,NC3,MM,row_major_layout>& u_,
+ matrix<T,NR4,NC4,MM,row_major_layout>& vt_
+ )
+ {
+ matrix<T,0,1,MM,row_major_layout> work;
+
+ // Row major order matrices are transposed from LAPACK's point of view.
+ matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;
+ matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;
+ std::swap(jobu, jobvt);
+
+ const long m = a.nc();
+ const long n = a.nr();
+ s.set_size(std::min(m,n), 1);
+
+ if (jobu == 'A')
+ u.set_size(m,m);
+ else if (jobu == 'S')
+ u.set_size(std::min(m,n), m);
+ else
+ u.set_size(NR4?NR4:1, NC4?NC4:1);
+
+ if (jobvt == 'A')
+ vt.set_size(n,n);
+ else if (jobvt == 'S')
+ vt.set_size(n, std::min(m,n));
+ else
+ vt.set_size(NR3?NR3:1, NC3?NC3:1);
+
+ if (jobu == 'O' || jobvt == 'O')
+ {
+ DLIB_CASSERT(false, "job == 'O' not supported");
+ }
+
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),
+ &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
+ &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual SVD
+ info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),
+ &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),
+ &work(0,0), work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_SVD_Hh_
+
diff --git a/ml/dlib/dlib/matrix/lapack/getrf.h b/ml/dlib/dlib/matrix/lapack/getrf.h
new file mode 100644
index 000000000..a1f0b139d
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/getrf.h
@@ -0,0 +1,132 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_GETRF_Hh_
+#define DLIB_LAPACk_GETRF_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dgetrf) (integer* m, integer *n, double *a,
+ integer* lda, integer *ipiv, integer *info);
+
+ void DLIB_FORTRAN_ID(sgetrf) (integer* m, integer *n, float *a,
+ integer* lda, integer *ipiv, integer *info);
+
+ }
+
+ inline int getrf (integer m, integer n, double *a,
+ integer lda, integer *ipiv)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dgetrf)(&m, &n, a, &lda, ipiv, &info);
+ return info;
+ }
+
+ inline int getrf (integer m, integer n, float *a,
+ integer lda, integer *ipiv)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sgetrf)(&m, &n, a, &lda, ipiv, &info);
+ return info;
+ }
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+
+/* -- LAPACK routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DGETRF computes an LU factorization of a general M-by-N matrix A */
+/* using partial pivoting with row interchanges. */
+
+/* The factorization has the form */
+/* A = P * L * U */
+/* where P is a permutation matrix, L is lower triangular with unit */
+/* diagonal elements (lower trapezoidal if m > n), and U is upper */
+/* triangular (upper trapezoidal if m < n). */
+
+/* This is the right-looking Level 3 BLAS version of the algorithm. */
+
+/* Arguments */
+/* ========= */
+
+/* M (input) INTEGER */
+/* The number of rows of the matrix A. M >= 0. */
+
+/* N (input) INTEGER */
+/* The number of columns of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the M-by-N matrix to be factored. */
+/* On exit, the factors L and U from the factorization */
+/* A = P*L*U; the unit diagonal elements of L are not stored. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,M). */
+
+/* IPIV (output) INTEGER array, dimension (min(M,N)) */
+/* The pivot indices; for 1 <= i <= min(M,N), row i of the */
+/* matrix was interchanged with row IPIV(i). */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value */
+/* > 0: if INFO = i, U(i,i) is exactly zero. The factorization */
+/* has been completed, but the factor U is exactly */
+/* singular, and division by zero will occur if it is used */
+/* to solve a system of equations. */
+
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2,
+ long NC1, long NC2,
+ typename MM,
+ typename layout
+ >
+ int getrf (
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<integer,NR2,NC2,MM,layout>& ipiv
+ )
+ {
+ const long m = a.nr();
+ const long n = a.nc();
+
+ ipiv.set_size(std::min(m,n), 1);
+
+ // compute the actual decomposition
+ return binding::getrf(m, n, &a(0,0), a.nr(), &ipiv(0,0));
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_GETRF_Hh_
+
diff --git a/ml/dlib/dlib/matrix/lapack/ormqr.h b/ml/dlib/dlib/matrix/lapack/ormqr.h
new file mode 100644
index 000000000..ab66ff4d2
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/ormqr.h
@@ -0,0 +1,224 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_ORMQR_Hh_
+#define DLIB_LAPACk_ORMQR_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dormqr) (char *side, char *trans, integer *m, integer *n,
+ integer *k, const double *a, integer *lda, const double *tau,
+ double * c_, integer *ldc, double *work, integer *lwork,
+ integer *info);
+
+ void DLIB_FORTRAN_ID(sormqr) (char *side, char *trans, integer *m, integer *n,
+ integer *k, const float *a, integer *lda, const float *tau,
+ float * c_, integer *ldc, float *work, integer *lwork,
+ integer *info);
+
+ }
+
+ inline int ormqr (char side, char trans, integer m, integer n,
+ integer k, const double *a, integer lda, const double *tau,
+ double *c_, integer ldc, double *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dormqr)(&side, &trans, &m, &n,
+ &k, a, &lda, tau,
+ c_, &ldc, work, &lwork, &info);
+ return info;
+ }
+
+ inline int ormqr (char side, char trans, integer m, integer n,
+ integer k, const float *a, integer lda, const float *tau,
+ float *c_, integer ldc, float *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(sormqr)(&side, &trans, &m, &n,
+ &k, a, &lda, tau,
+ c_, &ldc, work, &lwork, &info);
+ return info;
+ }
+
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DORMQR overwrites the general real M-by-N matrix C with */
+
+/* SIDE = 'L' SIDE = 'R' */
+/* TRANS = 'N': Q * C C * Q */
+/* TRANS = 'T': Q**T * C C * Q**T */
+
+/* where Q is a real orthogonal matrix defined as the product of k */
+/* elementary reflectors */
+
+/* Q = H(1) H(2) . . . H(k) */
+
+/* as returned by DGEQRF. Q is of order M if SIDE = 'L' and of order N */
+/* if SIDE = 'R'. */
+
+/* Arguments */
+/* ========= */
+
+/* SIDE (input) CHARACTER*1 */
+/* = 'L': apply Q or Q**T from the Left; */
+/* = 'R': apply Q or Q**T from the Right. */
+
+/* TRANS (input) CHARACTER*1 */
+/* = 'N': No transpose, apply Q; */
+/* = 'T': Transpose, apply Q**T. */
+
+/* M (input) INTEGER */
+/* The number of rows of the matrix C. M >= 0. */
+
+/* N (input) INTEGER */
+/* The number of columns of the matrix C. N >= 0. */
+
+/* K (input) INTEGER */
+/* The number of elementary reflectors whose product defines */
+/* the matrix Q. */
+/* If SIDE = 'L', M >= K >= 0; */
+/* if SIDE = 'R', N >= K >= 0. */
+
+/* A (input) DOUBLE PRECISION array, dimension (LDA,K) */
+/* The i-th column must contain the vector which defines the */
+/* elementary reflector H(i), for i = 1,2,...,k, as returned by */
+/* DGEQRF in the first k columns of its array argument A. */
+/* A is modified by the routine but restored on exit. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. */
+/* If SIDE = 'L', LDA >= max(1,M); */
+/* if SIDE = 'R', LDA >= max(1,N). */
+
+/* TAU (input) DOUBLE PRECISION array, dimension (K) */
+/* TAU(i) must contain the scalar factor of the elementary */
+/* reflector H(i), as returned by DGEQRF. */
+
+/* C (input/output) DOUBLE PRECISION array, dimension (LDC,N) */
+/* On entry, the M-by-N matrix C. */
+/* On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. */
+
+/* LDC (input) INTEGER */
+/* The leading dimension of the array C. LDC >= max(1,M). */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
+
+/* LWORK (input) INTEGER */
+/* The dimension of the array WORK. */
+/* If SIDE = 'L', LWORK >= max(1,N); */
+/* if SIDE = 'R', LWORK >= max(1,M). */
+/* For optimum performance LWORK >= N*NB if SIDE = 'L', and */
+/* LWORK >= M*NB if SIDE = 'R', where NB is the optimal */
+/* blocksize. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3,
+ long NC1, long NC2, long NC3,
+ typename MM,
+ typename C_LAYOUT
+ >
+ int ormqr (
+ char side,
+ char trans,
+ const matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ const matrix<T,NR2,NC2,MM,column_major_layout>& tau,
+ matrix<T,NR3,NC3,MM,C_LAYOUT>& c
+ )
+ {
+ long m = c.nr();
+ long n = c.nc();
+ const long k = a.nc();
+ long ldc;
+ if (is_same_type<C_LAYOUT,column_major_layout>::value)
+ {
+ ldc = c.nr();
+ }
+ else
+ {
+ // Since lapack expects c to be in column major layout we have to
+ // do something to make this work. Since a row major layout matrix
+ // will look just like a transposed C we can just swap a few things around.
+
+ ldc = c.nc();
+ swap(m,n);
+
+ if (side == 'L')
+ side = 'R';
+ else
+ side = 'L';
+
+ if (trans == 'T')
+ trans = 'N';
+ else
+ trans = 'T';
+ }
+
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::ormqr(side, trans, m, n,
+ k, &a(0,0), a.nr(), &tau(0,0),
+ &c(0,0), ldc, &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual result
+ info = binding::ormqr(side, trans, m, n,
+ k, &a(0,0), a.nr(), &tau(0,0),
+ &c(0,0), ldc, &work(0,0), work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_ORMQR_Hh_
+
diff --git a/ml/dlib/dlib/matrix/lapack/pbtrf.h b/ml/dlib/dlib/matrix/lapack/pbtrf.h
new file mode 100644
index 000000000..23bcc127b
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/pbtrf.h
@@ -0,0 +1,178 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_BDC_Hh_
+#define DLIB_LAPACk_BDC_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dpbtrf) (const char* uplo, const integer* n, const integer* kd,
+ double* ab, const integer* ldab, integer* info);
+
+ void DLIB_FORTRAN_ID(spbtrf) (const char* uplo, const integer* n, const integer* kd,
+ float* ab, const integer* ldab, integer* info);
+
+ }
+
+ inline integer pbtrf (const char uplo, const integer n, const integer kd,
+ double* ab, const integer ldab)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dpbtrf)(&uplo, &n, &kd, ab, &ldab, &info);
+ return info;
+ }
+
+ inline integer pbtrf (const char uplo, const integer n, const integer kd,
+ float* ab, const integer ldab)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(spbtrf)(&uplo, &n, &kd, ab, &ldab, &info);
+ return info;
+ }
+ }
+
+ // ------------------------------------------------------------------------------------
+/* DPBTRF(l) LAPACK routine (version 1.1) DPBTRF(l)
+
+NAME
+ DPBTRF - compute the Cholesky factorization of a real symmetric positive
+ definite band matrix A
+
+SYNOPSIS
+
+ SUBROUTINE DPBTRF( UPLO, N, KD, AB, LDAB, INFO )
+
+ CHARACTER UPLO
+
+ INTEGER INFO, KD, LDAB, N
+
+ DOUBLE PRECISION AB( LDAB, * )
+
+PURPOSE
+ DPBTRF computes the Cholesky factorization of a real symmetric positive
+ definite band matrix A.
+
+ The factorization has the form
+ A = U**T * U, if UPLO = 'U', or
+ A = L * L**T, if UPLO = 'L',
+ where U is an upper triangular matrix and L is lower triangular.
+
+ARGUMENTS
+
+ UPLO (input) CHARACTER*1
+ = 'U': Upper triangle of A is stored;
+ = 'L': Lower triangle of A is stored.
+
+ N (input) INTEGER
+ The order of the matrix A. N >= 0.
+
+ KD (input) INTEGER
+ The number of superdiagonals of the matrix A if UPLO = 'U', or the
+ number of subdiagonals if UPLO = 'L'. KD >= 0.
+
+ AB (input/output) DOUBLE PRECISION array, dimension (LDAB,N)
+ On entry, the upper or lower triangle of the symmetric band matrix
+ A, stored in the first KD+1 rows of the array. The j-th column of
+ A is stored in the j-th column of the array AB as follows: if UPLO
+ = 'U', AB(kd+1+i-j,j) = A(i,j) for max(1,j-kd)<=i<=j; if UPLO =
+ 'L', AB(1+i-j,j) = A(i,j) for j<=i<=min(n,j+kd).
+
+ On exit, if INFO = 0, the triangular factor U or L from the Chole-
+ sky factorization A = U**T*U or A = L*L**T of the band matrix A, in
+ the same storage format as A.
+
+ LDAB (input) INTEGER
+ The leading dimension of the array AB. LDAB >= KD+1.
+
+ INFO (output) INTEGER
+ = 0: successful exit
+ < 0: if INFO = -i, the i-th argument had an illegal value
+ > 0: if INFO = i, the leading minor of order i is not positive
+ definite, and the factorization could not be completed.
+
+FURTHER DETAILS
+ The band storage scheme is illustrated by the following example, when N =
+ 6, KD = 2, and UPLO = 'U':
+
+ On entry: On exit:
+
+ * * a13 a24 a35 a46 * * u13 u24 u35 u46
+ * a12 a23 a34 a45 a56 * u12 u23 u34 u45 u56
+ a11 a22 a33 a44 a55 a66 u11 u22 u33 u44 u55 u66
+
+ Similarly, if UPLO = 'L' the format of A is as follows:
+
+ On entry: On exit:
+
+ a11 a22 a33 a44 a55 a66 l11 l22 l33 l44 l55 l66
+ a21 a32 a43 a54 a65 * l21 l32 l43 l54 l65 *
+ a31 a42 a53 a64 * * l31 l42 l53 l64 * *
+
+ Array elements marked * are not used by the routine.
+
+ Contributed by
+ Peter Mayes and Giuseppe Radicati, IBM ECSEC, Rome, March 23, 1989 */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NC1,
+ typename MM
+ >
+ int pbtrf (
+ char uplo, matrix<T,NR1,NC1,MM,column_major_layout>& ab
+ )
+ {
+ const long ldab = ab.nr();
+ const long n = ab.nc();
+ const long kd = ldab - 1; // assume fully packed
+
+ int info = binding::pbtrf(uplo, n, kd, &ab(0,0), ldab);
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+
+ template <
+ typename T,
+ long NR1, long NC1,
+ typename MM
+ >
+ int pbtrf (
+ char uplo, matrix<T,NR1,NC1,MM,row_major_layout>& ab
+ )
+ {
+ const long ldab = ab.nr();
+ const long n = ab.nc();
+ const long kd = ldab - 1; // assume fully packed
+
+ matrix<T,NC1,NR1,MM,row_major_layout> abt = trans(ab);
+
+ int info = binding::pbtrf(uplo, n, kd, &abt(0,0), ldab);
+
+ ab = trans(abt);
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_BDC_Hh_
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/potrf.h b/ml/dlib/dlib/matrix/lapack/potrf.h
new file mode 100644
index 000000000..b9d6a7cc8
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/potrf.h
@@ -0,0 +1,174 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_POTRF_Hh_
+#define DLIB_LAPACk_POTRF_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dpotrf) (char *uplo, integer *n, double *a,
+ integer* lda, integer *info);
+
+ void DLIB_FORTRAN_ID(spotrf) (char *uplo, integer *n, float *a,
+ integer* lda, integer *info);
+
+ }
+
+ inline int potrf (char uplo, integer n, double *a, integer lda)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dpotrf)(&uplo, &n, a, &lda, &info);
+ return info;
+ }
+
+ inline int potrf (char uplo, integer n, float *a, integer lda)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(spotrf)(&uplo, &n, a, &lda, &info);
+ return info;
+ }
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DPOTRF computes the Cholesky factorization of a real symmetric */
+/* positive definite matrix A. */
+
+/* The factorization has the form */
+/* A = U**T * U, if UPLO = 'U', or */
+/* A = L * L**T, if UPLO = 'L', */
+/* where U is an upper triangular matrix and L is lower triangular. */
+
+/* This is the block version of the algorithm, calling Level 3 BLAS. */
+
+/* Arguments */
+/* ========= */
+
+/* UPLO (input) CHARACTER*1 */
+/* = 'U': Upper triangle of A is stored; */
+/* = 'L': Lower triangle of A is stored. */
+
+/* N (input) INTEGER */
+/* The order of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
+/* On entry, the symmetric matrix A. If UPLO = 'U', the leading */
+/* N-by-N upper triangular part of A contains the upper */
+/* triangular part of the matrix A, and the strictly lower */
+/* triangular part of A is not referenced. If UPLO = 'L', the */
+/* leading N-by-N lower triangular part of A contains the lower */
+/* triangular part of the matrix A, and the strictly upper */
+/* triangular part of A is not referenced. */
+
+/* On exit, if INFO = 0, the factor U or L from the Cholesky */
+/* factorization A = U**T*U or A = L*L**T. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,N). */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value */
+/* > 0: if INFO = i, the leading minor of order i is not */
+/* positive definite, and the factorization could not be */
+/* completed. */
+
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1,
+ long NC1,
+ typename MM
+ >
+ int potrf (
+ char uplo,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a
+ )
+ {
+ // compute the actual decomposition
+ int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());
+
+ // If it fails part way though the factorization then make sure
+ // the end of the matrix gets properly initialized with zeros.
+ if (info > 0)
+ {
+ if (uplo == 'L')
+ set_colm(a, range(info-1, a.nc()-1)) = 0;
+ else
+ set_rowm(a, range(info-1, a.nr()-1)) = 0;
+ }
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1,
+ long NC1,
+ typename MM
+ >
+ int potrf (
+ char uplo,
+ matrix<T,NR1,NC1,MM,row_major_layout>& a
+ )
+ {
+ // since we are working on a row major order matrix we need to ask
+ // LAPACK for the transpose of whatever the user asked for.
+
+ if (uplo == 'L')
+ uplo = 'U';
+ else
+ uplo = 'L';
+
+ // compute the actual decomposition
+ int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());
+
+ // If it fails part way though the factorization then make sure
+ // the end of the matrix gets properly initialized with zeros.
+ if (info > 0)
+ {
+ if (uplo == 'U')
+ set_colm(a, range(info-1, a.nc()-1)) = 0;
+ else
+ set_rowm(a, range(info-1, a.nr()-1)) = 0;
+ }
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_POTRF_Hh_
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/syev.h b/ml/dlib/dlib/matrix/lapack/syev.h
new file mode 100644
index 000000000..0c9fd251a
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/syev.h
@@ -0,0 +1,218 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_EV_Hh_
+#define DLIB_LAPACk_EV_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dsyev) (char *jobz, char *uplo, integer *n, double *a,
+ integer *lda, double *w, double *work, integer *lwork,
+ integer *info);
+
+ void DLIB_FORTRAN_ID(ssyev) (char *jobz, char *uplo, integer *n, float *a,
+ integer *lda, float *w, float *work, integer *lwork,
+ integer *info);
+
+ }
+
+ inline int syev (char jobz, char uplo, integer n, double *a,
+ integer lda, double *w, double *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dsyev)(&jobz, &uplo, &n, a,
+ &lda, w, work, &lwork, &info);
+ return info;
+ }
+
+ inline int syev (char jobz, char uplo, integer n, float *a,
+ integer lda, float *w, float *work, integer lwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(ssyev)(&jobz, &uplo, &n, a,
+ &lda, w, work, &lwork, &info);
+ return info;
+ }
+
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+/* -- LAPACK driver routine (version 3.1) -- */
+/* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */
+/* November 2006 */
+
+/* .. Scalar Arguments .. */
+/* .. */
+/* .. Array Arguments .. */
+/* .. */
+
+/* Purpose */
+/* ======= */
+
+/* DSYEV computes all eigenvalues and, optionally, eigenvectors of a */
+/* real symmetric matrix A. */
+
+/* Arguments */
+/* ========= */
+
+/* JOBZ (input) CHARACTER*1 */
+/* = 'N': Compute eigenvalues only; */
+/* = 'V': Compute eigenvalues and eigenvectors. */
+
+/* UPLO (input) CHARACTER*1 */
+/* = 'U': Upper triangle of A is stored; */
+/* = 'L': Lower triangle of A is stored. */
+
+/* N (input) INTEGER */
+/* The order of the matrix A. N >= 0. */
+
+/* A (input/output) DOUBLE PRECISION array, dimension (LDA, N) */
+/* On entry, the symmetric matrix A. If UPLO = 'U', the */
+/* leading N-by-N upper triangular part of A contains the */
+/* upper triangular part of the matrix A. If UPLO = 'L', */
+/* the leading N-by-N lower triangular part of A contains */
+/* the lower triangular part of the matrix A. */
+/* On exit, if JOBZ = 'V', then if INFO = 0, A contains the */
+/* orthonormal eigenvectors of the matrix A. */
+/* If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') */
+/* or the upper triangle (if UPLO='U') of A, including the */
+/* diagonal, is destroyed. */
+
+/* LDA (input) INTEGER */
+/* The leading dimension of the array A. LDA >= max(1,N). */
+
+/* W (output) DOUBLE PRECISION array, dimension (N) */
+/* If INFO = 0, the eigenvalues in ascending order. */
+
+/* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
+/* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
+
+/* LWORK (input) INTEGER */
+/* The length of the array WORK. LWORK >= max(1,3*N-1). */
+/* For optimal efficiency, LWORK >= (NB+2)*N, */
+/* where NB is the blocksize for DSYTRD returned by ILAENV. */
+
+/* If LWORK = -1, then a workspace query is assumed; the routine */
+/* only calculates the optimal size of the WORK array, returns */
+/* this value as the first entry of the WORK array, and no error */
+/* message related to LWORK is issued by XERBLA. */
+
+/* INFO (output) INTEGER */
+/* = 0: successful exit */
+/* < 0: if INFO = -i, the i-th argument had an illegal value */
+/* > 0: if INFO = i, the algorithm failed to converge; i */
+/* off-diagonal elements of an intermediate tridiagonal */
+/* form did not converge to zero. */
+
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2,
+ long NC1, long NC2,
+ typename MM
+ >
+ int syev (
+ const char jobz,
+ const char uplo,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ matrix<T,NR2,NC2,MM,column_major_layout>& w
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+
+ const long n = a.nr();
+
+ w.set_size(n,1);
+
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::syev(jobz, uplo, n, &a(0,0),
+ a.nr(), &w(0,0), &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual decomposition
+ info = binding::syev(jobz, uplo, n, &a(0,0),
+ a.nr(), &w(0,0), &work(0,0), work.size());
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2,
+ long NC1, long NC2,
+ typename MM
+ >
+ int syev (
+ char jobz,
+ char uplo,
+ matrix<T,NR1,NC1,MM,row_major_layout>& a,
+ matrix<T,NR2,NC2,MM,row_major_layout>& w
+ )
+ {
+ matrix<T,0,1,MM,row_major_layout> work;
+
+ if (uplo == 'L')
+ uplo = 'U';
+ else
+ uplo = 'L';
+
+ const long n = a.nr();
+
+ w.set_size(n,1);
+
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ int info = binding::syev(jobz, uplo, n, &a(0,0),
+ a.nc(), &w(0,0), &work_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+
+ // compute the actual decomposition
+ info = binding::syev(jobz, uplo, n, &a(0,0),
+ a.nc(), &w(0,0), &work(0,0), work.size());
+
+
+ a = trans(a);
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_EV_Hh_
+
+
+
+
diff --git a/ml/dlib/dlib/matrix/lapack/syevr.h b/ml/dlib/dlib/matrix/lapack/syevr.h
new file mode 100644
index 000000000..65190b3d8
--- /dev/null
+++ b/ml/dlib/dlib/matrix/lapack/syevr.h
@@ -0,0 +1,445 @@
+// Copyright (C) 2010 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_LAPACk_EVR_Hh_
+#define DLIB_LAPACk_EVR_Hh_
+
+#include "fortran_id.h"
+#include "../matrix.h"
+
+namespace dlib
+{
+ namespace lapack
+ {
+ namespace binding
+ {
+ extern "C"
+ {
+ void DLIB_FORTRAN_ID(dsyevr) (char *jobz, char *range, char *uplo, integer *n,
+ double *a, integer *lda, double *vl, double *vu, integer * il,
+ integer *iu, double *abstol, integer *m, double *w,
+ double *z_, integer *ldz, integer *isuppz, double *work,
+ integer *lwork, integer *iwork, integer *liwork, integer *info);
+
+ void DLIB_FORTRAN_ID(ssyevr) (char *jobz, char *range, char *uplo, integer *n,
+ float *a, integer *lda, float *vl, float *vu, integer * il,
+ integer *iu, float *abstol, integer *m, float *w,
+ float *z_, integer *ldz, integer *isuppz, float *work,
+ integer *lwork, integer *iwork, integer *liwork, integer *info);
+ }
+
+ inline int syevr (char jobz, char range, char uplo, integer n,
+ double* a, integer lda, double vl, double vu, integer il,
+ integer iu, double abstol, integer *m, double *w,
+ double *z, integer ldz, integer *isuppz, double *work,
+ integer lwork, integer *iwork, integer liwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(dsyevr)(&jobz, &range, &uplo, &n,
+ a, &lda, &vl, &vu, &il,
+ &iu, &abstol, m, w,
+ z, &ldz, isuppz, work,
+ &lwork, iwork, &liwork, &info);
+ return info;
+ }
+
+ inline int syevr (char jobz, char range, char uplo, integer n,
+ float* a, integer lda, float vl, float vu, integer il,
+ integer iu, float abstol, integer *m, float *w,
+ float *z, integer ldz, integer *isuppz, float *work,
+ integer lwork, integer *iwork, integer liwork)
+ {
+ integer info = 0;
+ DLIB_FORTRAN_ID(ssyevr)(&jobz, &range, &uplo, &n,
+ a, &lda, &vl, &vu, &il,
+ &iu, &abstol, m, w,
+ z, &ldz, isuppz, work,
+ &lwork, iwork, &liwork, &info);
+ return info;
+ }
+
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ /*
+
+* -- LAPACK driver routine (version 3.1) --
+* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..
+* November 2006
+*
+* .. Scalar Arguments ..
+ CHARACTER JOBZ, RANGE, UPLO
+ INTEGER IL, INFO, IU, LDA, LDZ, LIWORK, LWORK, M, N
+ DOUBLE PRECISION ABSTOL, VL, VU
+* ..
+* .. Array Arguments ..
+ INTEGER ISUPPZ( * ), IWORK( * )
+ DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * )
+* ..
+*
+* Purpose
+* =======
+*
+* DSYEVR computes selected eigenvalues and, optionally, eigenvectors
+* of a real symmetric matrix A. Eigenvalues and eigenvectors can be
+* selected by specifying either a range of values or a range of
+* indices for the desired eigenvalues.
+*
+* DSYEVR first reduces the matrix A to tridiagonal form T with a call
+* to DSYTRD. Then, whenever possible, DSYEVR calls DSTEMR to compute
+* the eigenspectrum using Relatively Robust Representations. DSTEMR
+* computes eigenvalues by the dqds algorithm, while orthogonal
+* eigenvectors are computed from various "good" L D L^T representations
+* (also known as Relatively Robust Representations). Gram-Schmidt
+* orthogonalization is avoided as far as possible. More specifically,
+* the various steps of the algorithm are as follows.
+*
+* For each unreduced block (submatrix) of T,
+* (a) Compute T - sigma I = L D L^T, so that L and D
+* define all the wanted eigenvalues to high relative accuracy.
+* This means that small relative changes in the entries of D and L
+* cause only small relative changes in the eigenvalues and
+* eigenvectors. The standard (unfactored) representation of the
+* tridiagonal matrix T does not have this property in general.
+* (b) Compute the eigenvalues to suitable accuracy.
+* If the eigenvectors are desired, the algorithm attains full
+* accuracy of the computed eigenvalues only right before
+* the corresponding vectors have to be computed, see steps c) and d).
+* (c) For each cluster of close eigenvalues, select a new
+* shift close to the cluster, find a new factorization, and refine
+* the shifted eigenvalues to suitable accuracy.
+* (d) For each eigenvalue with a large enough relative separation compute
+* the corresponding eigenvector by forming a rank revealing twisted
+* factorization. Go back to (c) for any clusters that remain.
+*
+* The desired accuracy of the output can be specified by the input
+* parameter ABSTOL.
+*
+* For more details, see DSTEMR's documentation and:
+* - Inderjit S. Dhillon and Beresford N. Parlett: "Multiple representations
+* to compute orthogonal eigenvectors of symmetric tridiagonal matrices,"
+* Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.
+* - Inderjit Dhillon and Beresford Parlett: "Orthogonal Eigenvectors and
+* Relative Gaps," SIAM Journal on Matrix Analysis and Applications, Vol. 25,
+* 2004. Also LAPACK Working Note 154.
+* - Inderjit Dhillon: "A new O(n^2) algorithm for the symmetric
+* tridiagonal eigenvalue/eigenvector problem",
+* Computer Science Division Technical Report No. UCB/CSD-97-971,
+* UC Berkeley, May 1997.
+*
+*
+* Note 1 : DSYEVR calls DSTEMR when the full spectrum is requested
+* on machines which conform to the ieee-754 floating point standard.
+* DSYEVR calls DSTEBZ and SSTEIN on non-ieee machines and
+* when partial spectrum requests are made.
+*
+* Normal execution of DSTEMR may create NaNs and infinities and
+* hence may abort due to a floating point exception in environments
+* which do not handle NaNs and infinities in the ieee standard default
+* manner.
+*
+* Arguments
+* =========
+*
+* JOBZ (input) CHARACTER*1
+* = 'N': Compute eigenvalues only;
+* = 'V': Compute eigenvalues and eigenvectors.
+*
+* RANGE (input) CHARACTER*1
+* = 'A': all eigenvalues will be found.
+* = 'V': all eigenvalues in the half-open interval (VL,VU]
+* will be found.
+* = 'I': the IL-th through IU-th eigenvalues will be found.
+********** For RANGE = 'V' or 'I' and IU - IL < N - 1, DSTEBZ and
+********** DSTEIN are called
+*
+* UPLO (input) CHARACTER*1
+* = 'U': Upper triangle of A is stored;
+* = 'L': Lower triangle of A is stored.
+*
+* N (input) INTEGER
+* The order of the matrix A. N >= 0.
+*
+* A (input/output) DOUBLE PRECISION array, dimension (LDA, N)
+* On entry, the symmetric matrix A. If UPLO = 'U', the
+* leading N-by-N upper triangular part of A contains the
+* upper triangular part of the matrix A. If UPLO = 'L',
+* the leading N-by-N lower triangular part of A contains
+* the lower triangular part of the matrix A.
+* On exit, the lower triangle (if UPLO='L') or the upper
+* triangle (if UPLO='U') of A, including the diagonal, is
+* destroyed.
+*
+* LDA (input) INTEGER
+* The leading dimension of the array A. LDA >= max(1,N).
+*
+* VL (input) DOUBLE PRECISION
+* VU (input) DOUBLE PRECISION
+* If RANGE='V', the lower and upper bounds of the interval to
+* be searched for eigenvalues. VL < VU.
+* Not referenced if RANGE = 'A' or 'I'.
+*
+* IL (input) INTEGER
+* IU (input) INTEGER
+* If RANGE='I', the indices (in ascending order) of the
+* smallest and largest eigenvalues to be returned.
+* 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.
+* Not referenced if RANGE = 'A' or 'V'.
+*
+* ABSTOL (input) DOUBLE PRECISION
+* The absolute error tolerance for the eigenvalues.
+* An approximate eigenvalue is accepted as converged
+* when it is determined to lie in an interval [a,b]
+* of width less than or equal to
+*
+* ABSTOL + EPS * max( |a|,|b| ) ,
+*
+* where EPS is the machine precision. If ABSTOL is less than
+* or equal to zero, then EPS*|T| will be used in its place,
+* where |T| is the 1-norm of the tridiagonal matrix obtained
+* by reducing A to tridiagonal form.
+*
+* See "Computing Small Singular Values of Bidiagonal Matrices
+* with Guaranteed High Relative Accuracy," by Demmel and
+* Kahan, LAPACK Working Note #3.
+*
+* If high relative accuracy is important, set ABSTOL to
+* DLAMCH( 'Safe minimum' ). Doing so will guarantee that
+* eigenvalues are computed to high relative accuracy when
+* possible in future releases. The current code does not
+* make any guarantees about high relative accuracy, but
+* future releases will. See J. Barlow and J. Demmel,
+* "Computing Accurate Eigensystems of Scaled Diagonally
+* Dominant Matrices", LAPACK Working Note #7, for a discussion
+* of which matrices define their eigenvalues to high relative
+* accuracy.
+*
+* M (output) INTEGER
+* The total number of eigenvalues found. 0 <= M <= N.
+* If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.
+*
+* W (output) DOUBLE PRECISION array, dimension (N)
+* The first M elements contain the selected eigenvalues in
+* ascending order.
+*
+* Z (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M))
+* If JOBZ = 'V', then if INFO = 0, the first M columns of Z
+* contain the orthonormal eigenvectors of the matrix A
+* corresponding to the selected eigenvalues, with the i-th
+* column of Z holding the eigenvector associated with W(i).
+* If JOBZ = 'N', then Z is not referenced.
+* Note: the user must ensure that at least max(1,M) columns are
+* supplied in the array Z; if RANGE = 'V', the exact value of M
+* is not known in advance and an upper bound must be used.
+* Supplying N columns is always safe.
+*
+* LDZ (input) INTEGER
+* The leading dimension of the array Z. LDZ >= 1, and if
+* JOBZ = 'V', LDZ >= max(1,N).
+*
+* ISUPPZ (output) INTEGER array, dimension ( 2*max(1,M) )
+* The support of the eigenvectors in Z, i.e., the indices
+* indicating the nonzero elements in Z. The i-th eigenvector
+* is nonzero only in elements ISUPPZ( 2*i-1 ) through
+* ISUPPZ( 2*i ).
+********** Implemented only for RANGE = 'A' or 'I' and IU - IL = N - 1
+*
+* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
+* On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
+*
+* LWORK (input) INTEGER
+* The dimension of the array WORK. LWORK >= max(1,26*N).
+* For optimal efficiency, LWORK >= (NB+6)*N,
+* where NB is the max of the blocksize for DSYTRD and DORMTR
+* returned by ILAENV.
+*
+* If LWORK = -1, then a workspace query is assumed; the routine
+* only calculates the optimal size of the WORK array, returns
+* this value as the first entry of the WORK array, and no error
+* message related to LWORK is issued by XERBLA.
+*
+* IWORK (workspace/output) INTEGER array, dimension (MAX(1,LIWORK))
+* On exit, if INFO = 0, IWORK(1) returns the optimal LWORK.
+*
+* LIWORK (input) INTEGER
+* The dimension of the array IWORK. LIWORK >= max(1,10*N).
+*
+* If LIWORK = -1, then a workspace query is assumed; the
+* routine only calculates the optimal size of the IWORK array,
+* returns this value as the first entry of the IWORK array, and
+* no error message related to LIWORK is issued by XERBLA.
+*
+* INFO (output) INTEGER
+* = 0: successful exit
+* < 0: if INFO = -i, the i-th argument had an illegal value
+* > 0: Internal error
+*
+* Further Details
+* ===============
+*
+* Based on contributions by
+* Inderjit Dhillon, IBM Almaden, USA
+* Osni Marques, LBNL/NERSC, USA
+* Ken Stanley, Computer Science Division, University of
+* California at Berkeley, USA
+* Jason Riedy, Computer Science Division, University of
+* California at Berkeley, USA
+*
+* =====================================================================
+
+ */
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int syevr (
+ const char jobz,
+ const char range,
+ const char uplo,
+ matrix<T,NR1,NC1,MM,column_major_layout>& a,
+ const double vl,
+ const double vu,
+ const integer il,
+ const integer iu,
+ const double abstol,
+ integer& num_eigenvalues_found,
+ matrix<T,NR2,NC2,MM,column_major_layout>& w,
+ matrix<T,NR3,NC3,MM,column_major_layout>& z,
+ matrix<integer,NR4,NC4,MM,column_major_layout>& isuppz
+ )
+ {
+ matrix<T,0,1,MM,column_major_layout> work;
+ matrix<integer,0,1,MM,column_major_layout> iwork;
+
+ const long n = a.nr();
+
+ w.set_size(n,1);
+
+ isuppz.set_size(2*n, 1);
+
+ if (jobz == 'V')
+ {
+ z.set_size(n,n);
+ }
+ else
+ {
+ z.set_size(NR3?NR3:1, NC3?NC3:1);
+ }
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ integer iwork_size = 1;
+ int info = binding::syevr(jobz, range, uplo, n, &a(0,0),
+ a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
+ &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work_size, -1,
+ &iwork_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+ if (iwork.size() < iwork_size)
+ iwork.set_size(iwork_size, 1);
+
+ // compute the actual decomposition
+ info = binding::syevr(jobz, range, uplo, n, &a(0,0),
+ a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
+ &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work(0,0), work.size(),
+ &iwork(0,0), iwork.size());
+
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ template <
+ typename T,
+ long NR1, long NR2, long NR3, long NR4,
+ long NC1, long NC2, long NC3, long NC4,
+ typename MM
+ >
+ int syevr (
+ const char jobz,
+ const char range,
+ char uplo,
+ matrix<T,NR1,NC1,MM,row_major_layout>& a,
+ const double vl,
+ const double vu,
+ const integer il,
+ const integer iu,
+ const double abstol,
+ integer& num_eigenvalues_found,
+ matrix<T,NR2,NC2,MM,row_major_layout>& w,
+ matrix<T,NR3,NC3,MM,row_major_layout>& z,
+ matrix<integer,NR4,NC4,MM,row_major_layout>& isuppz
+ )
+ {
+ matrix<T,0,1,MM,row_major_layout> work;
+ matrix<integer,0,1,MM,row_major_layout> iwork;
+
+ if (uplo == 'L')
+ uplo = 'U';
+ else
+ uplo = 'L';
+
+ const long n = a.nr();
+
+ w.set_size(n,1);
+
+ isuppz.set_size(2*n, 1);
+
+ if (jobz == 'V')
+ {
+ z.set_size(n,n);
+ }
+ else
+ {
+ z.set_size(NR3?NR3:1, NC3?NC3:1);
+ }
+
+ // figure out how big the workspace needs to be.
+ T work_size = 1;
+ integer iwork_size = 1;
+ int info = binding::syevr(jobz, range, uplo, n, &a(0,0),
+ a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
+ &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work_size, -1,
+ &iwork_size, -1);
+
+ if (info != 0)
+ return info;
+
+ if (work.size() < work_size)
+ work.set_size(static_cast<long>(work_size), 1);
+ if (iwork.size() < iwork_size)
+ iwork.set_size(iwork_size, 1);
+
+ // compute the actual decomposition
+ info = binding::syevr(jobz, range, uplo, n, &a(0,0),
+ a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,
+ &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work(0,0), work.size(),
+ &iwork(0,0), iwork.size());
+
+ z = trans(z);
+
+ return info;
+ }
+
+ // ------------------------------------------------------------------------------------
+
+ }
+
+}
+
+// ----------------------------------------------------------------------------------------
+
+#endif // DLIB_LAPACk_EVR_Hh_
+
+
+