26#if defined (HAVE_CONFIG_H)
31#include <unordered_map>
49 OCTAVE_DISABLE_CONSTRUCT_COPY_MOVE_DELETE (gejsv_lwork)
59 static F77_INT optimal (
char& joba,
char& jobu,
char& jobv,
63 typedef typename T::element_type P;
81 static F77_INT ormlq_lwork (
char& side,
char& trans,
87 static F77_INT ormqr_lwork (
char& side,
char& trans,
94#define GEJSV_REAL_QP3_LWORK(f, F) \
95 F77_XFCN (f, F, (m, n, a, lda, jpvt, tau, work, lwork, info))
97#define GEJSV_REAL_QR_LWORK(f, F) \
98 F77_XFCN (f, F, (m, n, a, lda, tau, work, lwork, info))
100#define GEJSV_REAL_ORM_LWORK(f, F) \
101 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&side, 1), \
102 F77_CONST_CHAR_ARG2 (&trans, 1), \
103 m, n, k, a, lda, tau, \
104 c, ldc, work, lwork, info \
105 F77_CHAR_ARG_LEN (1) \
106 F77_CHAR_ARG_LEN (1)))
113 F77_INT *jpvt, P *tau, P *work,
117 return static_cast<F77_INT> (work[0]);
128 return static_cast<F77_INT> (work[0]);
139 return static_cast<F77_INT> (work[0]);
144gejsv_lwork<Matrix>::ormlq_lwork (
char& side,
char& trans,
151 return static_cast<F77_INT> (work[0]);
156gejsv_lwork<Matrix>::ormqr_lwork (
char& side,
char& trans,
163 return static_cast<F77_INT> (work[0]);
171 F77_INT *jpvt, P *tau, P *work,
175 return static_cast<F77_INT> (work[0]);
186 return static_cast<F77_INT> (work[0]);
197 return static_cast<F77_INT> (work[0]);
202gejsv_lwork<FloatMatrix>::ormlq_lwork (
char& side,
char& trans,
209 return static_cast<F77_INT> (work[0]);
214gejsv_lwork<FloatMatrix>::ormqr_lwork (
char& side,
char& trans,
221 return static_cast<F77_INT> (work[0]);
224#undef GEJSV_REAL_QP3_LWORK
225#undef GEJSV_REAL_QR_LWORK
226#undef GEJSV_REAL_ORM_LWORK
230gejsv_lwork<T>::optimal (
char& joba,
char& jobu,
char& jobv,
234 std::vector<P> work (2);
237 F77_INT lda = std::max<F77_INT> (m, 1);
241 std::vector<P> mat_a (1);
242 P *a = mat_a.data ();
243 std::vector<F77_INT> vec_jpvt = {0};
244 P *tau = work.data ();
248 bool need_lsvec = jobu ==
'U' || jobu ==
'F';
249 bool need_rsvec = jobv ==
'V' || jobv ==
'J';
252 F77_INT lw_geqp3 = geqp3_lwork (m, n, a, lda, vec_jpvt.data (),
253 tau, work.data (), -1,
ierr);
254 F77_INT lw_geqrf = geqrf_lwork (m, n, a, lda,
255 tau, work.data (), -1,
ierr);
257 if (! (need_lsvec || need_rsvec) )
260 if (! (joba ==
'E' || joba ==
'G') )
261 lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_geqrf, 7});
263 lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_geqrf,
264 n + n*n + lw_pocon, 7});
266 else if (need_rsvec && ! need_lsvec)
269 F77_INT lw_gelqf = gelqf_lwork (n, n, a, lda,
270 tau, work.data (), -1,
ierr);
272 F77_INT lw_ormlq = ormlq_lwork (side, trans, n, n, n, a, lda,
273 tau, v, n, work.data (), -1,
ierr);
274 lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_pocon,
275 n + lw_gelqf, 2*n + lw_geqrf, n + lw_ormlq});
277 else if (need_lsvec && ! need_rsvec)
280 F77_INT n1 = (jobu ==
'U') ? n : m;
281 F77_INT lw_ormqr = ormqr_lwork (side, trans, m, n1, n, a, lda,
282 tau, u, m, work.data (), -1,
ierr);
283 lwork = std::max<F77_INT> ({2*m + n, n + lw_geqp3, n + lw_pocon,
284 2*n + lw_geqrf, n + lw_ormqr});
289 lwork = std::max (2*m + n, 6*n + 2*n*n);
290 else if (jobv ==
'J')
291 lwork = std::max<F77_INT> ({2*m + n, 4*n + n*n, 2*n + n*n + 6});
293 F77_INT n1 = (jobu ==
'U') ? n : m;
294 F77_INT lw_ormqr = ormqr_lwork (side, trans, m, n1, n, a, lda,
295 tau, u, m, work.data (), -1,
ierr);
296 lwork = std::max (lwork, n + lw_ormqr);
311 (*current_liboctave_error_handler)
312 (
"svd: U not computed because type == svd::sigma_only");
322 (*current_liboctave_error_handler)
323 (
"svd: V not computed because type == svd::sigma_only");
330#define GESVD_REAL_STEP(f, F) \
331 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1), \
332 F77_CONST_CHAR_ARG2 (&jobv, 1), \
333 m, n, tmp_data, m1, s_vec, u, m1, vt, \
334 nrow_vt1, work.data (), lwork, info \
335 F77_CHAR_ARG_LEN (1) \
336 F77_CHAR_ARG_LEN (1)))
338#define GESVD_COMPLEX_STEP(f, F, CMPLX_ARG) \
339 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobu, 1), \
340 F77_CONST_CHAR_ARG2 (&jobv, 1), \
341 m, n, CMPLX_ARG (tmp_data), \
342 m1, s_vec, CMPLX_ARG (u), m1, \
343 CMPLX_ARG (vt), nrow_vt1, \
344 CMPLX_ARG (work.data ()), \
345 lwork, rwork.data (), info \
346 F77_CHAR_ARG_LEN (1) \
347 F77_CHAR_ARG_LEN (1)))
353 double *tmp_data,
F77_INT m1,
double *s_vec,
354 double *u,
double *vt,
F77_INT nrow_vt1,
355 std::vector<double>& work,
F77_INT& lwork,
360 lwork =
static_cast<F77_INT> (work[0]);
361 work.reserve (lwork);
370 float *tmp_data,
F77_INT m1,
float *s_vec,
371 float *u,
float *vt,
F77_INT nrow_vt1,
372 std::vector<float>& work,
F77_INT& lwork,
377 lwork =
static_cast<F77_INT> (work[0]);
378 work.reserve (lwork);
389 std::vector<Complex>& work,
F77_INT& lwork,
392 std::vector<double> rwork (5 * std::max (m, n));
396 lwork =
static_cast<F77_INT> (work[0].real ());
397 work.reserve (lwork);
409 std::vector<FloatComplex>& work,
412 std::vector<float> rwork (5 * std::max (m, n));
416 lwork =
static_cast<F77_INT> (work[0].real ());
417 work.reserve (lwork);
422#undef GESVD_REAL_STEP
423#undef GESVD_COMPLEX_STEP
427#define GESDD_REAL_STEP(f, F) \
428 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobz, 1), \
429 m, n, tmp_data, m1, s_vec, u, m1, vt, nrow_vt1, \
430 work.data (), lwork, iwork, info \
431 F77_CHAR_ARG_LEN (1)))
433#define GESDD_COMPLEX_STEP(f, F, CMPLX_ARG) \
434 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&jobz, 1), m, n, \
435 CMPLX_ARG (tmp_data), m1, \
436 s_vec, CMPLX_ARG (u), m1, \
437 CMPLX_ARG (vt), nrow_vt1, \
438 CMPLX_ARG (work.data ()), lwork, \
439 rwork.data (), iwork, info \
440 F77_CHAR_ARG_LEN (1)))
446 F77_INT m1,
double *s_vec,
double *u,
double *vt,
447 F77_INT nrow_vt1, std::vector<double>& work,
452 lwork =
static_cast<F77_INT> (work[0]);
453 work.reserve (lwork);
462 F77_INT m1,
float *s_vec,
float *u,
float *vt,
463 F77_INT nrow_vt1, std::vector<float>& work,
468 lwork =
static_cast<F77_INT> (work[0]);
469 work.reserve (lwork);
480 std::vector<Complex>& work,
F77_INT& lwork,
484 F77_INT min_mn = std::min (m, n);
485 F77_INT max_mn = std::max (m, n);
491 lrwork = min_mn * std::max (5*min_mn+5, 2*max_mn+2*min_mn+1);
493 std::vector<double> rwork (lrwork);
497 lwork =
static_cast<F77_INT> (work[0].real ());
498 work.reserve (lwork);
510 std::vector<FloatComplex>& work,
514 F77_INT min_mn = std::min (m, n);
515 F77_INT max_mn = std::max (m, n);
521 lrwork = min_mn * std::max (5*min_mn+5, 2*max_mn+2*min_mn+1);
522 std::vector<float> rwork (lrwork);
526 lwork =
static_cast<F77_INT> (work[0].real ());
527 work.reserve (lwork);
532#undef GESDD_REAL_STEP
533#undef GESDD_COMPLEX_STEP
537#define GEJSV_REAL_STEP(f, F) \
538 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&joba, 1), \
539 F77_CONST_CHAR_ARG2 (&jobu, 1), \
540 F77_CONST_CHAR_ARG2 (&jobv, 1), \
541 F77_CONST_CHAR_ARG2 (&jobr, 1), \
542 F77_CONST_CHAR_ARG2 (&jobt, 1), \
543 F77_CONST_CHAR_ARG2 (&jobp, 1), \
544 m, n, tmp_data, m1, s_vec, u, m1, v, nrow_v1, \
545 work.data (), lwork, iwork.data (), info \
546 F77_CHAR_ARG_LEN (1) \
547 F77_CHAR_ARG_LEN (1) \
548 F77_CHAR_ARG_LEN (1) \
549 F77_CHAR_ARG_LEN (1) \
550 F77_CHAR_ARG_LEN (1) \
551 F77_CHAR_ARG_LEN (1)))
553#define GEJSV_COMPLEX_STEP(f, F, CMPLX_ARG) \
554 F77_XFCN (f, F, (F77_CONST_CHAR_ARG2 (&joba, 1), \
555 F77_CONST_CHAR_ARG2 (&jobu, 1), \
556 F77_CONST_CHAR_ARG2 (&jobv, 1), \
557 F77_CONST_CHAR_ARG2 (&jobr, 1), \
558 F77_CONST_CHAR_ARG2 (&jobt, 1), \
559 F77_CONST_CHAR_ARG2 (&jobp, 1), \
560 m, n, CMPLX_ARG (tmp_data), m1, \
561 s_vec, CMPLX_ARG (u), m1, \
562 CMPLX_ARG (v), nrow_v1, \
563 CMPLX_ARG (work.data ()), lwork, \
564 rwork.data (), lrwork, iwork.data (), info \
565 F77_CHAR_ARG_LEN (1) \
566 F77_CHAR_ARG_LEN (1) \
567 F77_CHAR_ARG_LEN (1) \
568 F77_CHAR_ARG_LEN (1) \
569 F77_CHAR_ARG_LEN (1) \
570 F77_CHAR_ARG_LEN (1)))
576 char& jobr,
char& jobt,
char& jobp,
578 P *tmp_data,
F77_INT m1, DM_P *s_vec, P *u,
579 P *v,
F77_INT nrow_v1, std::vector<P>& work,
580 F77_INT& lwork, std::vector<F77_INT>& iwork,
583 lwork = gejsv_lwork<Matrix>::optimal (joba, jobu, jobv, m, n);
584 work.reserve (lwork);
593 char& jobr,
char& jobt,
char& jobp,
595 P *tmp_data,
F77_INT m1, DM_P *s_vec, P *u,
596 P *v,
F77_INT nrow_v1, std::vector<P>& work,
597 F77_INT& lwork, std::vector<F77_INT>& iwork,
600 lwork = gejsv_lwork<FloatMatrix>::optimal (joba, jobu, jobv, m, n);
601 work.reserve (lwork);
610 char& jobr,
char& jobt,
char& jobp,
612 P *tmp_data,
F77_INT m1, DM_P *s_vec, P *u,
613 P *v,
F77_INT nrow_v1, std::vector<P>& work,
614 F77_INT& lwork, std::vector<F77_INT>& iwork,
618 std::vector<double> rwork (1);
623 lwork =
static_cast<F77_INT> (work[0].real ());
624 work.reserve (lwork);
626 lrwork =
static_cast<F77_INT> (rwork[0]);
627 rwork.reserve (lrwork);
630 iwork.reserve (liwork);
639 char& jobr,
char& jobt,
char& jobp,
641 F77_INT m1, DM_P *s_vec, P *u, P *v,
642 F77_INT nrow_v1, std::vector<P>& work,
644 std::vector<F77_INT>& iwork,
F77_INT& info)
647 std::vector<float> rwork (1);
652 lwork =
static_cast<F77_INT> (work[0].real ());
653 work.reserve (lwork);
655 lrwork =
static_cast<F77_INT> (rwork[0]);
656 rwork.reserve (lrwork);
659 iwork.reserve (liwork);
664#undef GEJSV_REAL_STEP
665#undef GEJSV_COMPLEX_STEP
669 : m_type (type), m_driver (driver), m_left_sm (), m_sigma (),
674 F77_INT m = to_f77_int (a.rows ());
675 F77_INT n = to_f77_int (a.cols ());
677 if (m == 0 || n == 0)
682 m_left_sm = T (m, m, 0);
683 for (
F77_INT i = 0; i < m; i++)
684 m_left_sm.xelem (i, i) = 1;
685 m_sigma =
DM_T (m, n);
686 m_right_sm = T (n, n, 0);
687 for (
F77_INT i = 0; i < n; i++)
688 m_right_sm.xelem (i, i) = 1;
692 m_left_sm = T (m, 0, 0);
693 m_sigma =
DM_T (0, 0);
694 m_right_sm = T (n, 0, 0);
699 m_sigma =
DM_T (0, 1);
706 P *tmp_data = atmp.rwdata ();
708 F77_INT min_mn = (m < n ? m : n);
722 ncol_u = nrow_vt = nrow_s = ncol_s = min_mn;
735 ncol_u = nrow_vt = 1;
742 if (! (jobu ==
'N' || jobu ==
'O'))
743 m_left_sm.resize (m, ncol_u);
745 P *u = m_left_sm.rwdata ();
747 m_sigma.resize (nrow_s, ncol_s);
748 DM_P *s_vec = m_sigma.rwdata ();
750 if (! (jobv ==
'N' || jobv ==
'O'))
753 m_right_sm.resize (n, nrow_vt);
755 m_right_sm.resize (nrow_vt, n);
758 P *vt = m_right_sm.rwdata ();
764 std::vector<P> work (1);
767 F77_INT m1 = std::max (m, f77_int_one);
768 F77_INT nrow_vt1 = std::max (nrow_vt, f77_int_one);
771 gesvd (jobu, jobv, m, n, tmp_data, m1, s_vec, u, vt, nrow_vt1,
778 std::vector<F77_INT> iwork (8 * std::min (m, n));
780 gesdd (jobz, m, n, tmp_data, m1, s_vec, u, vt, nrow_vt1,
781 work, lwork, iwork.data (), info);
785 bool transposed =
false;
792 m1 = std::max (m, f77_int_one);
793 nrow_vt1 = std::max (n, f77_int_one);
796 std::swap (jobu, jobv);
798 atmp = atmp.hermitian ();
799 tmp_data = atmp.rwdata ();
802 u = m_right_sm.rwdata ();
803 vt = m_left_sm.rwdata ();
807 std::unordered_map<char, std::string> job_svd2jsv;
808 job_svd2jsv[
'A'] =
"FJ";
809 job_svd2jsv[
'S'] =
"UV";
810 job_svd2jsv[
'O'] =
"WW";
811 job_svd2jsv[
'N'] =
"NN";
812 jobu = job_svd2jsv[jobu][0];
813 jobv = job_svd2jsv[jobv][1];
820 std::vector<F77_INT> iwork (std::max<F77_INT> (m + 3*n, 1));
822 gejsv (joba, jobu, jobv, jobr, jobt, jobp, m, n, tmp_data, m1,
823 s_vec, u, vt, nrow_vt1, work, lwork, iwork, info);
826 (*current_liboctave_warning_with_id_handler)
827 (
"Octave:convergence",
"svd: (driver: GEJSV) "
828 "Denormal occurred, possible loss of accuracy.");
831 (*current_liboctave_error_handler)
832 (
"svd: (driver: GEJSV) Illegal argument at #%d",
833 static_cast<int> (-info));
835 (*current_liboctave_warning_with_id_handler)
836 (
"Octave:convergence",
"svd: (driver: GEJSV) "
837 "Fail to converge within max sweeps, "
838 "possible inaccurate result.");
849 if (! m_sigma.dgxelem (i))
850 m_sigma.dgxelem (i) = DM_P (0);
855 m_right_sm = m_right_sm.hermitian ();
868OCTAVE_END_NAMESPACE(math)
869OCTAVE_END_NAMESPACE(octave)
T::real_diag_matrix_type DM_T
T right_singular_matrix() const
T left_singular_matrix() const
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
#define F77_DBLE_CMPLX_ARG(x)
octave_f77_int_type F77_INT
#define GESVD_REAL_STEP(f, F)
#define GESDD_COMPLEX_STEP(f, F, CMPLX_ARG)
#define GEJSV_REAL_STEP(f, F)
#define GEJSV_REAL_ORM_LWORK(f, F)
#define GEJSV_REAL_QR_LWORK(f, F)
#define GEJSV_COMPLEX_STEP(f, F, CMPLX_ARG)
#define GEJSV_REAL_QP3_LWORK(f, F)
#define GESDD_REAL_STEP(f, F)
#define GESVD_COMPLEX_STEP(f, F, CMPLX_ARG)
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
#define liboctave_panic_unless(cond)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE const F77_INT F77_INT & ierr
std::complex< double > Complex
std::complex< float > FloatComplex