File:  [local] / rpl / lapack / lapack / dgels.f
Revision 1.18: download - view: text, annotated - select for diffs - revision graph
Mon Aug 7 08:38:48 2023 UTC (9 months, 1 week ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_35, rpl-4_1_34, HEAD
Première mise à jour de lapack et blas.

    1: *> \brief <b> DGELS solves overdetermined or underdetermined systems for GE matrices</b>
    2: *
    3: *  =========== DOCUMENTATION ===========
    4: *
    5: * Online html documentation available at
    6: *            http://www.netlib.org/lapack/explore-html/
    7: *
    8: *> \htmlonly
    9: *> Download DGELS + dependencies
   10: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgels.f">
   11: *> [TGZ]</a>
   12: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgels.f">
   13: *> [ZIP]</a>
   14: *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgels.f">
   15: *> [TXT]</a>
   16: *> \endhtmlonly
   17: *
   18: *  Definition:
   19: *  ===========
   20: *
   21: *       SUBROUTINE DGELS( TRANS, M, N, NRHS, A, LDA, B, LDB, WORK, LWORK,
   22: *                         INFO )
   23: *
   24: *       .. Scalar Arguments ..
   25: *       CHARACTER          TRANS
   26: *       INTEGER            INFO, LDA, LDB, LWORK, M, N, NRHS
   27: *       ..
   28: *       .. Array Arguments ..
   29: *       DOUBLE PRECISION   A( LDA, * ), B( LDB, * ), WORK( * )
   30: *       ..
   31: *
   32: *
   33: *> \par Purpose:
   34: *  =============
   35: *>
   36: *> \verbatim
   37: *>
   38: *> DGELS solves overdetermined or underdetermined real linear systems
   39: *> involving an M-by-N matrix A, or its transpose, using a QR or LQ
   40: *> factorization of A.  It is assumed that A has full rank.
   41: *>
   42: *> The following options are provided:
   43: *>
   44: *> 1. If TRANS = 'N' and m >= n:  find the least squares solution of
   45: *>    an overdetermined system, i.e., solve the least squares problem
   46: *>                 minimize || B - A*X ||.
   47: *>
   48: *> 2. If TRANS = 'N' and m < n:  find the minimum norm solution of
   49: *>    an underdetermined system A * X = B.
   50: *>
   51: *> 3. If TRANS = 'T' and m >= n:  find the minimum norm solution of
   52: *>    an underdetermined system A**T * X = B.
   53: *>
   54: *> 4. If TRANS = 'T' and m < n:  find the least squares solution of
   55: *>    an overdetermined system, i.e., solve the least squares problem
   56: *>                 minimize || B - A**T * X ||.
   57: *>
   58: *> Several right hand side vectors b and solution vectors x can be
   59: *> handled in a single call; they are stored as the columns of the
   60: *> M-by-NRHS right hand side matrix B and the N-by-NRHS solution
   61: *> matrix X.
   62: *> \endverbatim
   63: *
   64: *  Arguments:
   65: *  ==========
   66: *
   67: *> \param[in] TRANS
   68: *> \verbatim
   69: *>          TRANS is CHARACTER*1
   70: *>          = 'N': the linear system involves A;
   71: *>          = 'T': the linear system involves A**T.
   72: *> \endverbatim
   73: *>
   74: *> \param[in] M
   75: *> \verbatim
   76: *>          M is INTEGER
   77: *>          The number of rows of the matrix A.  M >= 0.
   78: *> \endverbatim
   79: *>
   80: *> \param[in] N
   81: *> \verbatim
   82: *>          N is INTEGER
   83: *>          The number of columns of the matrix A.  N >= 0.
   84: *> \endverbatim
   85: *>
   86: *> \param[in] NRHS
   87: *> \verbatim
   88: *>          NRHS is INTEGER
   89: *>          The number of right hand sides, i.e., the number of
   90: *>          columns of the matrices B and X. NRHS >=0.
   91: *> \endverbatim
   92: *>
   93: *> \param[in,out] A
   94: *> \verbatim
   95: *>          A is DOUBLE PRECISION array, dimension (LDA,N)
   96: *>          On entry, the M-by-N matrix A.
   97: *>          On exit,
   98: *>            if M >= N, A is overwritten by details of its QR
   99: *>                       factorization as returned by DGEQRF;
  100: *>            if M <  N, A is overwritten by details of its LQ
  101: *>                       factorization as returned by DGELQF.
  102: *> \endverbatim
  103: *>
  104: *> \param[in] LDA
  105: *> \verbatim
  106: *>          LDA is INTEGER
  107: *>          The leading dimension of the array A.  LDA >= max(1,M).
  108: *> \endverbatim
  109: *>
  110: *> \param[in,out] B
  111: *> \verbatim
  112: *>          B is DOUBLE PRECISION array, dimension (LDB,NRHS)
  113: *>          On entry, the matrix B of right hand side vectors, stored
  114: *>          columnwise; B is M-by-NRHS if TRANS = 'N', or N-by-NRHS
  115: *>          if TRANS = 'T'.
  116: *>          On exit, if INFO = 0, B is overwritten by the solution
  117: *>          vectors, stored columnwise:
  118: *>          if TRANS = 'N' and m >= n, rows 1 to n of B contain the least
  119: *>          squares solution vectors; the residual sum of squares for the
  120: *>          solution in each column is given by the sum of squares of
  121: *>          elements N+1 to M in that column;
  122: *>          if TRANS = 'N' and m < n, rows 1 to N of B contain the
  123: *>          minimum norm solution vectors;
  124: *>          if TRANS = 'T' and m >= n, rows 1 to M of B contain the
  125: *>          minimum norm solution vectors;
  126: *>          if TRANS = 'T' and m < n, rows 1 to M of B contain the
  127: *>          least squares solution vectors; the residual sum of squares
  128: *>          for the solution in each column is given by the sum of
  129: *>          squares of elements M+1 to N in that column.
  130: *> \endverbatim
  131: *>
  132: *> \param[in] LDB
  133: *> \verbatim
  134: *>          LDB is INTEGER
  135: *>          The leading dimension of the array B. LDB >= MAX(1,M,N).
  136: *> \endverbatim
  137: *>
  138: *> \param[out] WORK
  139: *> \verbatim
  140: *>          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))
  141: *>          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
  142: *> \endverbatim
  143: *>
  144: *> \param[in] LWORK
  145: *> \verbatim
  146: *>          LWORK is INTEGER
  147: *>          The dimension of the array WORK.
  148: *>          LWORK >= max( 1, MN + max( MN, NRHS ) ).
  149: *>          For optimal performance,
  150: *>          LWORK >= max( 1, MN + max( MN, NRHS )*NB ).
  151: *>          where MN = min(M,N) and NB is the optimum block size.
  152: *>
  153: *>          If LWORK = -1, then a workspace query is assumed; the routine
  154: *>          only calculates the optimal size of the WORK array, returns
  155: *>          this value as the first entry of the WORK array, and no error
  156: *>          message related to LWORK is issued by XERBLA.
  157: *> \endverbatim
  158: *>
  159: *> \param[out] INFO
  160: *> \verbatim
  161: *>          INFO is INTEGER
  162: *>          = 0:  successful exit
  163: *>          < 0:  if INFO = -i, the i-th argument had an illegal value
  164: *>          > 0:  if INFO =  i, the i-th diagonal element of the
  165: *>                triangular factor of A is zero, so that A does not have
  166: *>                full rank; the least squares solution could not be
  167: *>                computed.
  168: *> \endverbatim
  169: *
  170: *  Authors:
  171: *  ========
  172: *
  173: *> \author Univ. of Tennessee
  174: *> \author Univ. of California Berkeley
  175: *> \author Univ. of Colorado Denver
  176: *> \author NAG Ltd.
  177: *
  178: *> \ingroup doubleGEsolve
  179: *
  180: *  =====================================================================
  181:       SUBROUTINE DGELS( TRANS, M, N, NRHS, A, LDA, B, LDB, WORK, LWORK,
  182:      $                  INFO )
  183: *
  184: *  -- LAPACK driver routine --
  185: *  -- LAPACK is a software package provided by Univ. of Tennessee,    --
  186: *  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  187: *
  188: *     .. Scalar Arguments ..
  189:       CHARACTER          TRANS
  190:       INTEGER            INFO, LDA, LDB, LWORK, M, N, NRHS
  191: *     ..
  192: *     .. Array Arguments ..
  193:       DOUBLE PRECISION   A( LDA, * ), B( LDB, * ), WORK( * )
  194: *     ..
  195: *
  196: *  =====================================================================
  197: *
  198: *     .. Parameters ..
  199:       DOUBLE PRECISION   ZERO, ONE
  200:       PARAMETER          ( ZERO = 0.0D0, ONE = 1.0D0 )
  201: *     ..
  202: *     .. Local Scalars ..
  203:       LOGICAL            LQUERY, TPSD
  204:       INTEGER            BROW, I, IASCL, IBSCL, J, MN, NB, SCLLEN, WSIZE
  205:       DOUBLE PRECISION   ANRM, BIGNUM, BNRM, SMLNUM
  206: *     ..
  207: *     .. Local Arrays ..
  208:       DOUBLE PRECISION   RWORK( 1 )
  209: *     ..
  210: *     .. External Functions ..
  211:       LOGICAL            LSAME
  212:       INTEGER            ILAENV
  213:       DOUBLE PRECISION   DLAMCH, DLANGE
  214:       EXTERNAL           LSAME, ILAENV, DLABAD, DLAMCH, DLANGE
  215: *     ..
  216: *     .. External Subroutines ..
  217:       EXTERNAL           DGELQF, DGEQRF, DLASCL, DLASET, DORMLQ, DORMQR,
  218:      $                   DTRTRS, XERBLA
  219: *     ..
  220: *     .. Intrinsic Functions ..
  221:       INTRINSIC          DBLE, MAX, MIN
  222: *     ..
  223: *     .. Executable Statements ..
  224: *
  225: *     Test the input arguments.
  226: *
  227:       INFO = 0
  228:       MN = MIN( M, N )
  229:       LQUERY = ( LWORK.EQ.-1 )
  230:       IF( .NOT.( LSAME( TRANS, 'N' ) .OR. LSAME( TRANS, 'T' ) ) ) THEN
  231:          INFO = -1
  232:       ELSE IF( M.LT.0 ) THEN
  233:          INFO = -2
  234:       ELSE IF( N.LT.0 ) THEN
  235:          INFO = -3
  236:       ELSE IF( NRHS.LT.0 ) THEN
  237:          INFO = -4
  238:       ELSE IF( LDA.LT.MAX( 1, M ) ) THEN
  239:          INFO = -6
  240:       ELSE IF( LDB.LT.MAX( 1, M, N ) ) THEN
  241:          INFO = -8
  242:       ELSE IF( LWORK.LT.MAX( 1, MN+MAX( MN, NRHS ) ) .AND. .NOT.LQUERY )
  243:      $          THEN
  244:          INFO = -10
  245:       END IF
  246: *
  247: *     Figure out optimal block size
  248: *
  249:       IF( INFO.EQ.0 .OR. INFO.EQ.-10 ) THEN
  250: *
  251:          TPSD = .TRUE.
  252:          IF( LSAME( TRANS, 'N' ) )
  253:      $      TPSD = .FALSE.
  254: *
  255:          IF( M.GE.N ) THEN
  256:             NB = ILAENV( 1, 'DGEQRF', ' ', M, N, -1, -1 )
  257:             IF( TPSD ) THEN
  258:                NB = MAX( NB, ILAENV( 1, 'DORMQR', 'LN', M, NRHS, N,
  259:      $              -1 ) )
  260:             ELSE
  261:                NB = MAX( NB, ILAENV( 1, 'DORMQR', 'LT', M, NRHS, N,
  262:      $              -1 ) )
  263:             END IF
  264:          ELSE
  265:             NB = ILAENV( 1, 'DGELQF', ' ', M, N, -1, -1 )
  266:             IF( TPSD ) THEN
  267:                NB = MAX( NB, ILAENV( 1, 'DORMLQ', 'LT', N, NRHS, M,
  268:      $              -1 ) )
  269:             ELSE
  270:                NB = MAX( NB, ILAENV( 1, 'DORMLQ', 'LN', N, NRHS, M,
  271:      $              -1 ) )
  272:             END IF
  273:          END IF
  274: *
  275:          WSIZE = MAX( 1, MN+MAX( MN, NRHS )*NB )
  276:          WORK( 1 ) = DBLE( WSIZE )
  277: *
  278:       END IF
  279: *
  280:       IF( INFO.NE.0 ) THEN
  281:          CALL XERBLA( 'DGELS ', -INFO )
  282:          RETURN
  283:       ELSE IF( LQUERY ) THEN
  284:          RETURN
  285:       END IF
  286: *
  287: *     Quick return if possible
  288: *
  289:       IF( MIN( M, N, NRHS ).EQ.0 ) THEN
  290:          CALL DLASET( 'Full', MAX( M, N ), NRHS, ZERO, ZERO, B, LDB )
  291:          RETURN
  292:       END IF
  293: *
  294: *     Get machine parameters
  295: *
  296:       SMLNUM = DLAMCH( 'S' ) / DLAMCH( 'P' )
  297:       BIGNUM = ONE / SMLNUM
  298:       CALL DLABAD( SMLNUM, BIGNUM )
  299: *
  300: *     Scale A, B if max element outside range [SMLNUM,BIGNUM]
  301: *
  302:       ANRM = DLANGE( 'M', M, N, A, LDA, RWORK )
  303:       IASCL = 0
  304:       IF( ANRM.GT.ZERO .AND. ANRM.LT.SMLNUM ) THEN
  305: *
  306: *        Scale matrix norm up to SMLNUM
  307: *
  308:          CALL DLASCL( 'G', 0, 0, ANRM, SMLNUM, M, N, A, LDA, INFO )
  309:          IASCL = 1
  310:       ELSE IF( ANRM.GT.BIGNUM ) THEN
  311: *
  312: *        Scale matrix norm down to BIGNUM
  313: *
  314:          CALL DLASCL( 'G', 0, 0, ANRM, BIGNUM, M, N, A, LDA, INFO )
  315:          IASCL = 2
  316:       ELSE IF( ANRM.EQ.ZERO ) THEN
  317: *
  318: *        Matrix all zero. Return zero solution.
  319: *
  320:          CALL DLASET( 'F', MAX( M, N ), NRHS, ZERO, ZERO, B, LDB )
  321:          GO TO 50
  322:       END IF
  323: *
  324:       BROW = M
  325:       IF( TPSD )
  326:      $   BROW = N
  327:       BNRM = DLANGE( 'M', BROW, NRHS, B, LDB, RWORK )
  328:       IBSCL = 0
  329:       IF( BNRM.GT.ZERO .AND. BNRM.LT.SMLNUM ) THEN
  330: *
  331: *        Scale matrix norm up to SMLNUM
  332: *
  333:          CALL DLASCL( 'G', 0, 0, BNRM, SMLNUM, BROW, NRHS, B, LDB,
  334:      $                INFO )
  335:          IBSCL = 1
  336:       ELSE IF( BNRM.GT.BIGNUM ) THEN
  337: *
  338: *        Scale matrix norm down to BIGNUM
  339: *
  340:          CALL DLASCL( 'G', 0, 0, BNRM, BIGNUM, BROW, NRHS, B, LDB,
  341:      $                INFO )
  342:          IBSCL = 2
  343:       END IF
  344: *
  345:       IF( M.GE.N ) THEN
  346: *
  347: *        compute QR factorization of A
  348: *
  349:          CALL DGEQRF( M, N, A, LDA, WORK( 1 ), WORK( MN+1 ), LWORK-MN,
  350:      $                INFO )
  351: *
  352: *        workspace at least N, optimally N*NB
  353: *
  354:          IF( .NOT.TPSD ) THEN
  355: *
  356: *           Least-Squares Problem min || A * X - B ||
  357: *
  358: *           B(1:M,1:NRHS) := Q**T * B(1:M,1:NRHS)
  359: *
  360:             CALL DORMQR( 'Left', 'Transpose', M, NRHS, N, A, LDA,
  361:      $                   WORK( 1 ), B, LDB, WORK( MN+1 ), LWORK-MN,
  362:      $                   INFO )
  363: *
  364: *           workspace at least NRHS, optimally NRHS*NB
  365: *
  366: *           B(1:N,1:NRHS) := inv(R) * B(1:N,1:NRHS)
  367: *
  368:             CALL DTRTRS( 'Upper', 'No transpose', 'Non-unit', N, NRHS,
  369:      $                   A, LDA, B, LDB, INFO )
  370: *
  371:             IF( INFO.GT.0 ) THEN
  372:                RETURN
  373:             END IF
  374: *
  375:             SCLLEN = N
  376: *
  377:          ELSE
  378: *
  379: *           Underdetermined system of equations A**T * X = B
  380: *
  381: *           B(1:N,1:NRHS) := inv(R**T) * B(1:N,1:NRHS)
  382: *
  383:             CALL DTRTRS( 'Upper', 'Transpose', 'Non-unit', N, NRHS,
  384:      $                   A, LDA, B, LDB, INFO )
  385: *
  386:             IF( INFO.GT.0 ) THEN
  387:                RETURN
  388:             END IF
  389: *
  390: *           B(N+1:M,1:NRHS) = ZERO
  391: *
  392:             DO 20 J = 1, NRHS
  393:                DO 10 I = N + 1, M
  394:                   B( I, J ) = ZERO
  395:    10          CONTINUE
  396:    20       CONTINUE
  397: *
  398: *           B(1:M,1:NRHS) := Q(1:N,:) * B(1:N,1:NRHS)
  399: *
  400:             CALL DORMQR( 'Left', 'No transpose', M, NRHS, N, A, LDA,
  401:      $                   WORK( 1 ), B, LDB, WORK( MN+1 ), LWORK-MN,
  402:      $                   INFO )
  403: *
  404: *           workspace at least NRHS, optimally NRHS*NB
  405: *
  406:             SCLLEN = M
  407: *
  408:          END IF
  409: *
  410:       ELSE
  411: *
  412: *        Compute LQ factorization of A
  413: *
  414:          CALL DGELQF( M, N, A, LDA, WORK( 1 ), WORK( MN+1 ), LWORK-MN,
  415:      $                INFO )
  416: *
  417: *        workspace at least M, optimally M*NB.
  418: *
  419:          IF( .NOT.TPSD ) THEN
  420: *
  421: *           underdetermined system of equations A * X = B
  422: *
  423: *           B(1:M,1:NRHS) := inv(L) * B(1:M,1:NRHS)
  424: *
  425:             CALL DTRTRS( 'Lower', 'No transpose', 'Non-unit', M, NRHS,
  426:      $                   A, LDA, B, LDB, INFO )
  427: *
  428:             IF( INFO.GT.0 ) THEN
  429:                RETURN
  430:             END IF
  431: *
  432: *           B(M+1:N,1:NRHS) = 0
  433: *
  434:             DO 40 J = 1, NRHS
  435:                DO 30 I = M + 1, N
  436:                   B( I, J ) = ZERO
  437:    30          CONTINUE
  438:    40       CONTINUE
  439: *
  440: *           B(1:N,1:NRHS) := Q(1:N,:)**T * B(1:M,1:NRHS)
  441: *
  442:             CALL DORMLQ( 'Left', 'Transpose', N, NRHS, M, A, LDA,
  443:      $                   WORK( 1 ), B, LDB, WORK( MN+1 ), LWORK-MN,
  444:      $                   INFO )
  445: *
  446: *           workspace at least NRHS, optimally NRHS*NB
  447: *
  448:             SCLLEN = N
  449: *
  450:          ELSE
  451: *
  452: *           overdetermined system min || A**T * X - B ||
  453: *
  454: *           B(1:N,1:NRHS) := Q * B(1:N,1:NRHS)
  455: *
  456:             CALL DORMLQ( 'Left', 'No transpose', N, NRHS, M, A, LDA,
  457:      $                   WORK( 1 ), B, LDB, WORK( MN+1 ), LWORK-MN,
  458:      $                   INFO )
  459: *
  460: *           workspace at least NRHS, optimally NRHS*NB
  461: *
  462: *           B(1:M,1:NRHS) := inv(L**T) * B(1:M,1:NRHS)
  463: *
  464:             CALL DTRTRS( 'Lower', 'Transpose', 'Non-unit', M, NRHS,
  465:      $                   A, LDA, B, LDB, INFO )
  466: *
  467:             IF( INFO.GT.0 ) THEN
  468:                RETURN
  469:             END IF
  470: *
  471:             SCLLEN = M
  472: *
  473:          END IF
  474: *
  475:       END IF
  476: *
  477: *     Undo scaling
  478: *
  479:       IF( IASCL.EQ.1 ) THEN
  480:          CALL DLASCL( 'G', 0, 0, ANRM, SMLNUM, SCLLEN, NRHS, B, LDB,
  481:      $                INFO )
  482:       ELSE IF( IASCL.EQ.2 ) THEN
  483:          CALL DLASCL( 'G', 0, 0, ANRM, BIGNUM, SCLLEN, NRHS, B, LDB,
  484:      $                INFO )
  485:       END IF
  486:       IF( IBSCL.EQ.1 ) THEN
  487:          CALL DLASCL( 'G', 0, 0, SMLNUM, BNRM, SCLLEN, NRHS, B, LDB,
  488:      $                INFO )
  489:       ELSE IF( IBSCL.EQ.2 ) THEN
  490:          CALL DLASCL( 'G', 0, 0, BIGNUM, BNRM, SCLLEN, NRHS, B, LDB,
  491:      $                INFO )
  492:       END IF
  493: *
  494:    50 CONTINUE
  495:       WORK( 1 ) = DBLE( WSIZE )
  496: *
  497:       RETURN
  498: *
  499: *     End of DGELS
  500: *
  501:       END

CVSweb interface <joel.bertrand@systella.fr>