comparison liboctave/CMatrix.cc @ 7476:e9f10b4c05cf

fix workspace size calculation for xGELSD
author Jason Riedy
date Tue, 12 Feb 2008 21:04:27 -0500
parents a7a987b229b7
children 8b22207ef9ca
comparison
equal deleted inserted replaced
7475:aa5208636bea 7476:e9f10b4c05cf
61 61
62 // Fortran functions we call. 62 // Fortran functions we call.
63 63
64 extern "C" 64 extern "C"
65 { 65 {
66 octave_idx_type
67 F77_FUNC (ilaenv, ILAENV) (const octave_idx_type&, F77_CONST_CHAR_ARG_DECL,
68 F77_CONST_CHAR_ARG_DECL,
69 const octave_idx_type&, const octave_idx_type&,
70 const octave_idx_type&, const octave_idx_type&
71 F77_CHAR_ARG_LEN_DECL F77_CHAR_ARG_LEN_DECL);
72
66 F77_RET_T 73 F77_RET_T
67 F77_FUNC (zgebal, ZGEBAL) (F77_CONST_CHAR_ARG_DECL, 74 F77_FUNC (zgebal, ZGEBAL) (F77_CONST_CHAR_ARG_DECL,
68 const octave_idx_type&, Complex*, const octave_idx_type&, octave_idx_type&, 75 const octave_idx_type&, Complex*, const octave_idx_type&, octave_idx_type&,
69 octave_idx_type&, double*, octave_idx_type& 76 octave_idx_type&, double*, octave_idx_type&
70 F77_CHAR_ARG_LEN_DECL); 77 F77_CHAR_ARG_LEN_DECL);
2490 // Ask ZGELSD what the dimension of WORK should be. 2497 // Ask ZGELSD what the dimension of WORK should be.
2491 octave_idx_type lwork = -1; 2498 octave_idx_type lwork = -1;
2492 2499
2493 Array<Complex> work (1); 2500 Array<Complex> work (1);
2494 2501
2495 // FIXME: Can SMLSIZ be other than 25? 2502 const octave_idx_type smlsiz
2496 octave_idx_type smlsiz = 25; 2503 = F77_FUNC (ilaenv, ILAENV) (9, F77_CONST_CHAR_ARG2 ("ZGELSD", 6),
2504 F77_CONST_CHAR_ARG2 (" ", 1),
2505 0, 0, 0, 0
2506 F77_CHAR_ARG_LEN (6)
2507 F77_CHAR_ARG_LEN (1));
2497 2508
2498 // We compute the size of rwork and iwork because ZGELSD in 2509 // We compute the size of rwork and iwork because ZGELSD in
2499 // older versions of LAPACK does not return them on a query 2510 // older versions of LAPACK does not return them on a query
2500 // call. 2511 // call.
2501 double dminmn = static_cast<double> (minmn); 2512 double dminmn = static_cast<double> (minmn);
2523 octave_idx_type* piwork = iwork.fortran_vec (); 2534 octave_idx_type* piwork = iwork.fortran_vec ();
2524 2535
2525 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn, 2536 F77_XFCN (zgelsd, ZGELSD, (m, n, nrhs, tmp_data, m, pretval, maxmn,
2526 ps, rcond, rank, work.fortran_vec (), 2537 ps, rcond, rank, work.fortran_vec (),
2527 lwork, prwork, piwork, info)); 2538 lwork, prwork, piwork, info));
2539
2540 // The workspace query is broken in at least LAPACK 3.0.0
2541 // through 3.1.1 when n > m. The obtuse formula below
2542 // should provide sufficient workspace for DGELSD to operate
2543 // efficiently.
2544 if (n > m)
2545 {
2546 octave_idx_type addend = m;
2547
2548 if (2*m-4 > addend)
2549 addend = 2*m-4;
2550
2551 if (nrhs > addend)
2552 addend = nrhs;
2553
2554 if (n-3*m > addend)
2555 addend = n-3*m;
2556
2557 const octave_idx_type lworkaround = 4*m + m*m + addend;
2558
2559 if (std::real (work(0)) < lworkaround)
2560 work(0) = lworkaround;
2561 }
2528 2562
2529 if (f77_exception_encountered) 2563 if (f77_exception_encountered)
2530 (*current_liboctave_error_handler) 2564 (*current_liboctave_error_handler)
2531 ("unrecoverable error in zgelsd"); 2565 ("unrecoverable error in zgelsd");
2532 else 2566 else