numeric-linalg

Educational material on the SciPy implementation of numerical linear algebra algorithms

NameSizeMode
..
lapack/SRC/slaqp3rk.f 34456B -rw-r--r--
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
*> \brief \b SLAQP3RK computes a step of truncated QR factorization with column pivoting of a real m-by-n matrix A using Level 3 BLAS and overwrites a real m-by-nrhs matrix B with Q**T * B.
*
*  =========== DOCUMENTATION ===========
*
* Online html documentation available at
*            http://www.netlib.org/lapack/explore-html/
*
*> \htmlonly
*> Download SLAQP3RK + dependencies
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/slaqp3rk.f">
*> [TGZ]</a>
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/slaqp3rk.f">
*> [ZIP]</a>
*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/slaqp3rk.f">
*> [TXT]</a>
*> \endhtmlonly
*
*  Definition:
*  ===========
*
*      SUBROUTINE SLAQP3RK( M, N, NRHS, IOFFSET, NB, ABSTOL,
*     $                     RELTOL, KP1, MAXC2NRM, A, LDA, DONE, KB,
*     $                     MAXC2NRMK, RELMAXC2NRMK, JPIV, TAU,
*     $                     VN1, VN2, AUXV, F, LDF, IWORK, INFO )
*      IMPLICIT NONE
*      LOGICAL            DONE
*      INTEGER            INFO, IOFFSET, KB, KP1, LDA, LDF, M, N,
*     $                   NB, NRHS
*      REAL               ABSTOL, MAXC2NRM, MAXC2NRMK, RELMAXC2NRMK,
*     $                   RELTOL
*
*     .. Scalar Arguments ..
*      LOGICAL            DONE
*      INTEGER            KB, LDA, LDF, M, N, NB, NRHS, IOFFSET
*      REAL               ABSTOL, MAXC2NRM, MAXC2NRMK, RELMAXC2NRMK,
*     $                   RELTOL
*     ..
*     .. Array Arguments ..
*      INTEGER            IWORK( * ), JPIV( * )
*      REAL               A( LDA, * ), AUXV( * ), F( LDF, * ), TAU( * ),
*     $                   VN1( * ), VN2( * )
*     ..
*
*
*> \par Purpose:
*  =============
*>
*> \verbatim
*>
*> SLAQP3RK computes a step of truncated QR factorization with column
*> pivoting of a real M-by-N matrix A block A(IOFFSET+1:M,1:N)
*> by using Level 3 BLAS as
*>
*>   A * P(KB) = Q(KB) * R(KB).
*>
*> The routine tries to factorize NB columns from A starting from
*> the row IOFFSET+1 and updates the residual matrix with BLAS 3
*> xGEMM. The number of actually factorized columns is returned
*> is smaller than NB.
*>
*> Block A(1:IOFFSET,1:N) is accordingly pivoted, but not factorized.
*>
*> The routine also overwrites the right-hand-sides B matrix stored
*> in A(IOFFSET+1:M,1:N+1:N+NRHS) with Q(KB)**T * B.
*>
*> Cases when the number of factorized columns KB < NB:
*>
*> (1) In some cases, due to catastrophic cancellations, it cannot
*> factorize all NB columns and need to update the residual matrix.
*> Hence, the actual number of factorized columns in the block returned
*> in KB is smaller than NB. The logical DONE is returned as FALSE.
*> The factorization of the whole original matrix A_orig must proceed
*> with the next block.
*>
*> (2) Whenever the stopping criterion ABSTOL or RELTOL is satisfied,
*> the factorization of the whole original matrix A_orig is stopped,
*> the logical DONE is returned as TRUE. The number of factorized
*> columns which is smaller than NB is returned in KB.
*>
*> (3) In case both stopping criteria ABSTOL or RELTOL are not used,
*> and when the residual matrix is a zero matrix in some factorization
*> step KB, the factorization of the whole original matrix A_orig is
*> stopped, the logical DONE is returned as TRUE. The number of
*> factorized columns which is smaller than NB is returned in KB.
*>
*> (4) Whenever NaN is detected in the matrix A or in the array TAU,
*> the factorization of the whole original matrix A_orig is stopped,
*> the logical DONE is returned as TRUE. The number of factorized
*> columns which is smaller than NB is returned in KB. The INFO
*> parameter is set to the column index of the first NaN occurrence.
*>
*> \endverbatim
*
*  Arguments:
*  ==========
*
*> \param[in] M
*> \verbatim
*>          M is INTEGER
*>          The number of rows of the matrix A. M >= 0.
*> \endverbatim
*>
*> \param[in] N
*> \verbatim
*>          N is INTEGER
*>          The number of columns of the matrix A. N >= 0
*> \endverbatim
*>
*> \param[in] NRHS
*> \verbatim
*>          NRHS is INTEGER
*>          The number of right hand sides, i.e., the number of
*>          columns of the matrix B. NRHS >= 0.
*> \endverbatim
*>
*> \param[in] IOFFSET
*> \verbatim
*>          IOFFSET is INTEGER
*>          The number of rows of the matrix A that must be pivoted
*>          but not factorized. IOFFSET >= 0.
*>
*>          IOFFSET also represents the number of columns of the whole
*>          original matrix A_orig that have been factorized
*>          in the previous steps.
*> \endverbatim
*>
*> \param[in] NB
*> \verbatim
*>          NB is INTEGER
*>          Factorization block size, i.e the number of columns
*>          to factorize in the matrix A. 0 <= NB
*>
*>          If NB = 0, then the routine exits immediately.
*>             This means that the factorization is not performed,
*>             the matrices A and B and the arrays TAU, IPIV
*>             are not modified.
*> \endverbatim
*>
*> \param[in] ABSTOL
*> \verbatim
*>          ABSTOL is REAL, cannot be NaN.
*>
*>          The absolute tolerance (stopping threshold) for
*>          maximum column 2-norm of the residual matrix.
*>          The algorithm converges (stops the factorization) when
*>          the maximum column 2-norm of the residual matrix
*>          is less than or equal to ABSTOL.
*>
*>          a) If ABSTOL < 0.0, then this stopping criterion is not
*>                used, the routine factorizes columns depending
*>                on NB and RELTOL.
*>                This includes the case ABSTOL = -Inf.
*>
*>          b) If 0.0 <= ABSTOL then the input value
*>                of ABSTOL is used.
*> \endverbatim
*>
*> \param[in] RELTOL
*> \verbatim
*>          RELTOL is REAL, cannot be NaN.
*>
*>          The tolerance (stopping threshold) for the ratio of the
*>          maximum column 2-norm of the residual matrix to the maximum
*>          column 2-norm of the original matrix A_orig. The algorithm
*>          converges (stops the factorization), when this ratio is
*>          less than or equal to RELTOL.
*>
*>          a) If RELTOL < 0.0, then this stopping criterion is not
*>                used, the routine factorizes columns depending
*>                on NB and ABSTOL.
*>                This includes the case RELTOL = -Inf.
*>
*>          d) If 0.0 <= RELTOL then the input value of RELTOL
*>                is used.
*> \endverbatim
*>
*> \param[in] KP1
*> \verbatim
*>          KP1 is INTEGER
*>          The index of the column with the maximum 2-norm in
*>          the whole original matrix A_orig determined in the
*>          main routine SGEQP3RK. 1 <= KP1 <= N_orig.
*> \endverbatim
*>
*> \param[in] MAXC2NRM
*> \verbatim
*>          MAXC2NRM is REAL
*>          The maximum column 2-norm of the whole original
*>          matrix A_orig computed in the main routine SGEQP3RK.
*>          MAXC2NRM >= 0.
*> \endverbatim
*>
*> \param[in,out] A
*> \verbatim
*>          A is REAL array, dimension (LDA,N+NRHS)
*>          On entry:
*>              the M-by-N matrix A and M-by-NRHS matrix B, as in
*>
*>                                  N     NRHS
*>              array_A   =   M  [ mat_A, mat_B ]
*>
*>          On exit:
*>          1. The elements in block A(IOFFSET+1:M,1:KB) below
*>             the diagonal together with the array TAU represent
*>             the orthogonal matrix Q(KB) as a product of elementary
*>             reflectors.
*>          2. The upper triangular block of the matrix A stored
*>             in A(IOFFSET+1:M,1:KB) is the triangular factor obtained.
*>          3. The block of the matrix A stored in A(1:IOFFSET,1:N)
*>             has been accordingly pivoted, but not factorized.
*>          4. The rest of the array A, block A(IOFFSET+1:M,KB+1:N+NRHS).
*>             The left part A(IOFFSET+1:M,KB+1:N) of this block
*>             contains the residual of the matrix A, and,
*>             if NRHS > 0, the right part of the block
*>             A(IOFFSET+1:M,N+1:N+NRHS) contains the block of
*>             the right-hand-side matrix B. Both these blocks have been
*>             updated by multiplication from the left by Q(KB)**T.
*> \endverbatim
*>
*> \param[in] LDA
*> \verbatim
*>          LDA is INTEGER
*>          The leading dimension of the array A. LDA >= max(1,M).
*> \endverbatim
*>
*> \param[out] DONE
*> \verbatim
*>          DONE is LOGICAL
*>          TRUE: a) if the factorization completed before processing
*>                   all min(M-IOFFSET,NB,N) columns due to ABSTOL
*>                   or RELTOL criterion,
*>                b) if the factorization completed before processing
*>                   all min(M-IOFFSET,NB,N) columns due to the
*>                   residual matrix being a ZERO matrix.
*>                c) when NaN was detected in the matrix A
*>                   or in the array TAU.
*>          FALSE: otherwise.
*> \endverbatim
*>
*> \param[out] KB
*> \verbatim
*>          KB is INTEGER
*>          Factorization rank of the matrix A, i.e. the rank of
*>          the factor R, which is the same as the number of non-zero
*>          rows of the factor R.  0 <= KB <= min(M-IOFFSET,NB,N).
*>
*>          KB also represents the number of non-zero Householder
*>          vectors.
*> \endverbatim
*>
*> \param[out] MAXC2NRMK
*> \verbatim
*>          MAXC2NRMK is REAL
*>          The maximum column 2-norm of the residual matrix,
*>          when the factorization stopped at rank KB. MAXC2NRMK >= 0.
*> \endverbatim
*>
*> \param[out] RELMAXC2NRMK
*> \verbatim
*>          RELMAXC2NRMK is REAL
*>          The ratio MAXC2NRMK / MAXC2NRM of the maximum column
*>          2-norm of the residual matrix (when the factorization
*>          stopped at rank KB) to the maximum column 2-norm of the
*>          original matrix A_orig. RELMAXC2NRMK >= 0.
*> \endverbatim
*>
*> \param[out] JPIV
*> \verbatim
*>          JPIV is INTEGER array, dimension (N)
*>          Column pivot indices, for 1 <= j <= N, column j
*>          of the matrix A was interchanged with column JPIV(j).
*> \endverbatim
*>
*> \param[out] TAU
*> \verbatim
*>          TAU is REAL array, dimension (min(M-IOFFSET,N))
*>          The scalar factors of the elementary reflectors.
*> \endverbatim
*>
*> \param[in,out] VN1
*> \verbatim
*>          VN1 is REAL array, dimension (N)
*>          The vector with the partial column norms.
*> \endverbatim
*>
*> \param[in,out] VN2
*> \verbatim
*>          VN2 is REAL array, dimension (N)
*>          The vector with the exact column norms.
*> \endverbatim
*>
*> \param[out] AUXV
*> \verbatim
*>          AUXV is REAL array, dimension (NB)
*>          Auxiliary vector.
*> \endverbatim
*>
*> \param[out] F
*> \verbatim
*>          F is REAL array, dimension (LDF,NB)
*>          Matrix F**T = L*(Y**T)*A.
*> \endverbatim
*>
*> \param[in] LDF
*> \verbatim
*>          LDF is INTEGER
*>          The leading dimension of the array F. LDF >= max(1,N+NRHS).
*> \endverbatim
*>
*> \param[out] IWORK
*> \verbatim
*>          IWORK is INTEGER array, dimension (N-1).
*>          Is a work array. ( IWORK is used to store indices
*>          of "bad" columns for norm downdating in the residual
*>          matrix ).
*> \endverbatim
*>
*> \param[out] INFO
*> \verbatim
*>          INFO is INTEGER
*>          1) INFO = 0: successful exit.
*>          2) If INFO = j_1, where 1 <= j_1 <= N, then NaN was
*>             detected and the routine stops the computation.
*>             The j_1-th column of the matrix A or the j_1-th
*>             element of array TAU contains the first occurrence
*>             of NaN in the factorization step KB+1 ( when KB columns
*>             have been factorized ).
*>
*>             On exit:
*>             KB                  is set to the number of
*>                                    factorized columns without
*>                                    exception.
*>             MAXC2NRMK           is set to NaN.
*>             RELMAXC2NRMK        is set to NaN.
*>             TAU(KB+1:min(M,N))     is not set and contains undefined
*>                                    elements. If j_1=KB+1, TAU(KB+1)
*>                                    may contain NaN.
*>          3) If INFO = j_2, where N+1 <= j_2 <= 2*N, then no NaN
*>             was detected, but +Inf (or -Inf) was detected and
*>             the routine continues the computation until completion.
*>             The (j_2-N)-th column of the matrix A contains the first
*>             occurrence of +Inf (or -Inf) in the actorization
*>             step KB+1 ( when KB columns have been factorized ).
*> \endverbatim
*
*  Authors:
*  ========
*
*> \author Univ. of Tennessee
*> \author Univ. of California Berkeley
*> \author Univ. of Colorado Denver
*> \author NAG Ltd.
*
*> \ingroup laqp3rk
*
*> \par References:
*  ================
*> [1] A Level 3 BLAS QR factorization algorithm with column pivoting developed in 1996.
*> G. Quintana-Orti, Depto. de Informatica, Universidad Jaime I, Spain.
*> X. Sun, Computer Science Dept., Duke University, USA.
*> C. H. Bischof, Math. and Comp. Sci. Div., Argonne National Lab, USA.
*> A BLAS-3 version of the QR factorization with column pivoting.
*> LAPACK Working Note 114
*> \htmlonly
*> <a href="https://www.netlib.org/lapack/lawnspdf/lawn114.pdf">https://www.netlib.org/lapack/lawnspdf/lawn114.pdf</a>
*> \endhtmlonly
*> and in
*> SIAM J. Sci. Comput., 19(5):1486-1494, Sept. 1998.
*> \htmlonly
*> <a href="https://doi.org/10.1137/S1064827595296732">https://doi.org/10.1137/S1064827595296732</a>
*> \endhtmlonly
*>
*> [2] A partial column norm updating strategy developed in 2006.
*> Z. Drmac and Z. Bujanovic, Dept. of Math., University of Zagreb, Croatia.
*> On the failure of rank revealing QR factorization software – a case study.
*> LAPACK Working Note 176.
*> \htmlonly
*> <a href="http://www.netlib.org/lapack/lawnspdf/lawn176.pdf">http://www.netlib.org/lapack/lawnspdf/lawn176.pdf</a>
*> \endhtmlonly
*> and in
*> ACM Trans. Math. Softw. 35, 2, Article 12 (July 2008), 28 pages.
*> \htmlonly
*> <a href="https://doi.org/10.1145/1377612.1377616">https://doi.org/10.1145/1377612.1377616</a>
*> \endhtmlonly
*
*> \par Contributors:
*  ==================
*>
*> \verbatim
*>
*>  November  2023, Igor Kozachenko, James Demmel,
*>                  EECS Department,
*>                  University of California, Berkeley, USA.
*>
*> \endverbatim
*
*  =====================================================================
      SUBROUTINE SLAQP3RK( M, N, NRHS, IOFFSET, NB, ABSTOL,
     $                     RELTOL, KP1, MAXC2NRM, A, LDA, DONE, KB,
     $                     MAXC2NRMK, RELMAXC2NRMK, JPIV, TAU,
     $                     VN1, VN2, AUXV, F, LDF, IWORK, INFO )
      IMPLICIT NONE
*
*  -- LAPACK auxiliary routine --
*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
*
*     .. Scalar Arguments ..
      LOGICAL            DONE
      INTEGER            INFO, IOFFSET, KB, KP1, LDA, LDF, M, N,
     $                   NB, NRHS
      REAL               ABSTOL, MAXC2NRM, MAXC2NRMK, RELMAXC2NRMK,
     $                   RELTOL
*     ..
*     .. Array Arguments ..
      INTEGER            IWORK( * ), JPIV( * )
      REAL               A( LDA, * ), AUXV( * ), F( LDF, * ), TAU( * ),
     $                   VN1( * ), VN2( * )
*     ..
*
*  =====================================================================
*
*     .. Parameters ..
      REAL               ZERO, ONE
      PARAMETER          ( ZERO = 0.0E+0, ONE = 1.0E+0 )
*     ..
*     .. Local Scalars ..
      INTEGER            ITEMP, J, K, MINMNFACT, MINMNUPDT,
     $                   LSTICC, KP, I, IF
      REAL               AIK, HUGEVAL, TEMP, TEMP2, TOL3Z
*     ..
*     .. External Subroutines ..
      EXTERNAL           SGEMM, SGEMV, SLARFG, SSWAP
*     ..
*     .. Intrinsic Functions ..
      INTRINSIC          ABS, MAX, MIN, SQRT
*     ..
*     .. External Functions ..
      LOGICAL            SISNAN
      INTEGER            ISAMAX
      REAL               SLAMCH, SNRM2
      EXTERNAL           SISNAN, SLAMCH, ISAMAX, SNRM2
*     ..
*     .. Executable Statements ..
*
*     Initialize INFO
*
      INFO = 0
*
*     MINMNFACT in the smallest dimension of the submatrix
*     A(IOFFSET+1:M,1:N) to be factorized.
*
      MINMNFACT = MIN( M-IOFFSET, N )
      MINMNUPDT = MIN( M-IOFFSET, N+NRHS )
      NB = MIN( NB, MINMNFACT )
      TOL3Z = SQRT( SLAMCH( 'Epsilon' ) )
      HUGEVAL = SLAMCH( 'Overflow' )
*
*     Compute factorization in a while loop over NB columns,
*     K is the column index in the block A(1:M,1:N).
*
      K = 0
      LSTICC = 0
      DONE = .FALSE.
*
      DO WHILE ( K.LT.NB .AND. LSTICC.EQ.0 )
         K = K + 1
         I = IOFFSET + K
*
         IF( I.EQ.1 ) THEN
*
*           We are at the first column of the original whole matrix A_orig,
*           therefore we use the computed KP1 and MAXC2NRM from the
*           main routine.
*
            KP = KP1
*
         ELSE
*
*           Determine the pivot column in K-th step, i.e. the index
*           of the column with the maximum 2-norm in the
*           submatrix A(I:M,K:N).
*
            KP = ( K-1 ) + ISAMAX( N-K+1, VN1( K ), 1 )
*
*           Determine the maximum column 2-norm and the relative maximum
*           column 2-norm of the submatrix A(I:M,K:N) in step K.
*
            MAXC2NRMK = VN1( KP )
*
*           ============================================================
*
*           Check if the submatrix A(I:M,K:N) contains NaN, set
*           INFO parameter to the column number, where the first NaN
*           is found and return from the routine.
*           We need to check the condition only if the
*           column index (same as row index) of the original whole
*           matrix is larger than 1, since the condition for whole
*           original matrix is checked in the main routine.
*
            IF( SISNAN( MAXC2NRMK ) ) THEN
*
               DONE = .TRUE.
*
*              Set KB, the number of factorized partial columns
*                      that are non-zero in each step in the block,
*                      i.e. the rank of the factor R.
*              Set IF, the number of processed rows in the block, which
*                      is the same as the number of processed rows in
*                      the original whole matrix A_orig.
*
               KB = K - 1
               IF = I - 1
               INFO = KB + KP
*
*              Set RELMAXC2NRMK to NaN.
*
               RELMAXC2NRMK = MAXC2NRMK
*
*              There is no need to apply the block reflector to the
*              residual of the matrix A stored in A(KB+1:M,KB+1:N),
*              since the submatrix contains NaN and we stop
*              the computation.
*              But, we need to apply the block reflector to the residual
*              right hand sides stored in A(KB+1:M,N+1:N+NRHS), if the
*              residual right hand sides exist.  This occurs
*              when ( NRHS != 0 AND KB <= (M-IOFFSET) ):
*
*              A(I+1:M,N+1:N+NRHS) := A(I+1:M,N+1:N+NRHS) -
*                               A(I+1:M,1:KB) * F(N+1:N+NRHS,1:KB)**T.

               IF( NRHS.GT.0 .AND. KB.LT.(M-IOFFSET) ) THEN
                  CALL SGEMM( 'No transpose', 'Transpose',
     $                  M-IF, NRHS, KB, -ONE, A( IF+1, 1 ), LDA,
     $                  F( N+1, 1 ), LDF, ONE, A( IF+1, N+1 ), LDA )
               END IF
*
*              There is no need to recompute the 2-norm of the
*              difficult columns, since we stop the factorization.
*
*              Array TAU(KF+1:MINMNFACT) is not set and contains
*              undefined elements.
*
*              Return from the routine.
*
               RETURN
            END IF
*
*           Quick return, if the submatrix A(I:M,K:N) is
*           a zero matrix. We need to check it only if the column index
*           (same as row index) is larger than 1, since the condition
*           for the whole original matrix A_orig is checked in the main
*           routine.
*
            IF( MAXC2NRMK.EQ.ZERO ) THEN
*
               DONE = .TRUE.
*
*              Set KB, the number of factorized partial columns
*                      that are non-zero in each step in the block,
*                      i.e. the rank of the factor R.
*              Set IF, the number of processed rows in the block, which
*                      is the same as the number of processed rows in
*                      the original whole matrix A_orig.
*
               KB = K - 1
               IF = I - 1
               RELMAXC2NRMK = ZERO
*
*              There is no need to apply the block reflector to the
*              residual of the matrix A stored in A(KB+1:M,KB+1:N),
*              since the submatrix is zero and we stop the computation.
*              But, we need to apply the block reflector to the residual
*              right hand sides stored in A(KB+1:M,N+1:N+NRHS), if the
*              residual right hand sides exist.  This occurs
*              when ( NRHS != 0 AND KB <= (M-IOFFSET) ):
*
*              A(I+1:M,N+1:N+NRHS) := A(I+1:M,N+1:N+NRHS) -
*                               A(I+1:M,1:KB) * F(N+1:N+NRHS,1:KB)**T.
*
               IF( NRHS.GT.0 .AND. KB.LT.(M-IOFFSET) ) THEN
                  CALL SGEMM( 'No transpose', 'Transpose',
     $                  M-IF, NRHS, KB, -ONE, A( IF+1, 1 ), LDA,
     $                  F( N+1, 1 ), LDF, ONE, A( IF+1, N+1 ), LDA )
               END IF
*
*              There is no need to recompute the 2-norm of the
*              difficult columns, since we stop the factorization.
*
*              Set TAUs corresponding to the columns that were not
*              factorized to ZERO, i.e. set TAU(KB+1:MINMNFACT) = ZERO,
*              which is equivalent to seting TAU(K:MINMNFACT) = ZERO.
*
               DO J = K, MINMNFACT
                  TAU( J ) = ZERO
               END DO
*
*              Return from the routine.
*
               RETURN
*
            END IF
*
*           ============================================================
*
*           Check if the submatrix A(I:M,K:N) contains Inf,
*           set INFO parameter to the column number, where
*           the first Inf is found plus N, and continue
*           the computation.
*           We need to check the condition only if the
*           column index (same as row index) of the original whole
*           matrix is larger than 1, since the condition for whole
*           original matrix is checked in the main routine.
*
            IF( INFO.EQ.0 .AND. MAXC2NRMK.GT.HUGEVAL ) THEN
               INFO = N + K - 1 + KP
            END IF
*
*           ============================================================
*
*           Test for the second and third tolerance stopping criteria.
*           NOTE: There is no need to test for ABSTOL.GE.ZERO, since
*           MAXC2NRMK is non-negative. Similarly, there is no need
*           to test for RELTOL.GE.ZERO, since RELMAXC2NRMK is
*           non-negative.
*           We need to check the condition only if the
*           column index (same as row index) of the original whole
*           matrix is larger than 1, since the condition for whole
*           original matrix is checked in the main routine.
*
            RELMAXC2NRMK =  MAXC2NRMK / MAXC2NRM
*
            IF( MAXC2NRMK.LE.ABSTOL .OR. RELMAXC2NRMK.LE.RELTOL ) THEN
*
               DONE = .TRUE.
*
*              Set KB, the number of factorized partial columns
*                      that are non-zero in each step in the block,
*                      i.e. the rank of the factor R.
*              Set IF, the number of processed rows in the block, which
*                      is the same as the number of processed rows in
*                      the original whole matrix A_orig;
*
                  KB = K - 1
                  IF = I - 1
*
*              Apply the block reflector to the residual of the
*              matrix A and the residual of the right hand sides B, if
*              the residual matrix and and/or the residual of the right
*              hand sides exist,  i.e. if the submatrix
*              A(I+1:M,KB+1:N+NRHS) exists.  This occurs when
*                 KB < MINMNUPDT = min( M-IOFFSET, N+NRHS ):
*
*              A(IF+1:M,K+1:N+NRHS) := A(IF+1:M,KB+1:N+NRHS) -
*                             A(IF+1:M,1:KB) * F(KB+1:N+NRHS,1:KB)**T.
*
               IF( KB.LT.MINMNUPDT ) THEN
                  CALL SGEMM( 'No transpose', 'Transpose',
     $                  M-IF, N+NRHS-KB, KB,-ONE, A( IF+1, 1 ), LDA,
     $                  F( KB+1, 1 ), LDF, ONE, A( IF+1, KB+1 ), LDA )
               END IF
*
*              There is no need to recompute the 2-norm of the
*              difficult columns, since we stop the factorization.
*
*              Set TAUs corresponding to the columns that were not
*              factorized to ZERO, i.e. set TAU(KB+1:MINMNFACT) = ZERO,
*              which is equivalent to seting TAU(K:MINMNFACT) = ZERO.
*
               DO J = K, MINMNFACT
                  TAU( J ) = ZERO
               END DO
*
*              Return from the routine.
*
               RETURN
*
            END IF
*
*           ============================================================
*
*           End ELSE of IF(I.EQ.1)
*
         END IF
*
*        ===============================================================
*
*        If the pivot column is not the first column of the
*        subblock A(1:M,K:N):
*        1) swap the K-th column and the KP-th pivot column
*           in A(1:M,1:N);
*        2) swap the K-th row and the KP-th row in F(1:N,1:K-1)
*        3) copy the K-th element into the KP-th element of the partial
*           and exact 2-norm vectors VN1 and VN2. (Swap is not needed
*           for VN1 and VN2 since we use the element with the index
*           larger than K in the next loop step.)
*        4) Save the pivot interchange with the indices relative to the
*           the original matrix A_orig, not the block A(1:M,1:N).
*
         IF( KP.NE.K ) THEN
            CALL SSWAP( M, A( 1, KP ), 1, A( 1, K ), 1 )
            CALL SSWAP( K-1, F( KP, 1 ), LDF, F( K, 1 ), LDF )
            VN1( KP ) = VN1( K )
            VN2( KP ) = VN2( K )
            ITEMP = JPIV( KP )
            JPIV( KP ) = JPIV( K )
            JPIV( K ) = ITEMP
         END IF
*
*        Apply previous Householder reflectors to column K:
*        A(I:M,K) := A(I:M,K) - A(I:M,1:K-1)*F(K,1:K-1)**T.
*
         IF( K.GT.1 ) THEN
            CALL SGEMV( 'No transpose', M-I+1, K-1, -ONE, A( I, 1 ),
     $                  LDA, F( K, 1 ), LDF, ONE, A( I, K ), 1 )
         END IF
*
*        Generate elementary reflector H(k) using the column A(I:M,K).
*
         IF( I.LT.M ) THEN
            CALL SLARFG( M-I+1, A( I, K ), A( I+1, K ), 1, TAU( K ) )
         ELSE
            TAU( K ) = ZERO
         END IF
*
*        Check if TAU(K) contains NaN, set INFO parameter
*        to the column number where NaN is found and return from
*        the routine.
*        NOTE: There is no need to check TAU(K) for Inf,
*        since SLARFG cannot produce TAU(K) or Householder vector
*        below the diagonal containing Inf. Only BETA on the diagonal,
*        returned by SLARFG can contain Inf, which requires
*        TAU(K) to contain NaN. Therefore, this case of generating Inf
*        by SLARFG is covered by checking TAU(K) for NaN.
*
         IF( SISNAN( TAU(K) ) ) THEN
*
            DONE = .TRUE.
*
*           Set KB, the number of factorized partial columns
*                   that are non-zero in each step in the block,
*                   i.e. the rank of the factor R.
*           Set IF, the number of processed rows in the block, which
*                   is the same as the number of processed rows in
*                   the original whole matrix A_orig.
*
            KB = K - 1
            IF = I - 1
            INFO = K
*
*           Set MAXC2NRMK and  RELMAXC2NRMK to NaN.
*
            MAXC2NRMK = TAU( K )
            RELMAXC2NRMK = TAU( K )
*
*           There is no need to apply the block reflector to the
*           residual of the matrix A stored in A(KB+1:M,KB+1:N),
*           since the submatrix contains NaN and we stop
*           the computation.
*           But, we need to apply the block reflector to the residual
*           right hand sides stored in A(KB+1:M,N+1:N+NRHS), if the
*           residual right hand sides exist.  This occurs
*           when ( NRHS != 0 AND KB <= (M-IOFFSET) ):
*
*           A(I+1:M,N+1:N+NRHS) := A(I+1:M,N+1:N+NRHS) -
*                            A(I+1:M,1:KB) * F(N+1:N+NRHS,1:KB)**T.
*
            IF( NRHS.GT.0 .AND. KB.LT.(M-IOFFSET) ) THEN
               CALL SGEMM( 'No transpose', 'Transpose',
     $               M-IF, NRHS, KB, -ONE, A( IF+1, 1 ), LDA,
     $               F( N+1, 1 ), LDF, ONE, A( IF+1, N+1 ), LDA )
            END IF
*
*           There is no need to recompute the 2-norm of the
*           difficult columns, since we stop the factorization.
*
*           Array TAU(KF+1:MINMNFACT) is not set and contains
*           undefined elements.
*
*           Return from the routine.
*
            RETURN
         END IF
*
*        ===============================================================
*
         AIK = A( I, K )
         A( I, K ) = ONE
*
*        ===============================================================
*
*        Compute the current K-th column of F:
*          1) F(K+1:N,K) := tau(K) * A(I:M,K+1:N)**T * A(I:M,K).
*
         IF( K.LT.N+NRHS ) THEN
            CALL SGEMV( 'Transpose', M-I+1, N+NRHS-K,
     $                  TAU( K ), A( I, K+1 ), LDA, A( I, K ), 1,
     $                  ZERO, F( K+1, K ), 1 )
         END IF
*
*           2) Zero out elements above and on the diagonal of the
*              column K in matrix F, i.e elements F(1:K,K).
*
         DO J = 1, K
            F( J, K ) = ZERO
         END DO
*
*         3) Incremental updating of the K-th column of F:
*        F(1:N,K) := F(1:N,K) - tau(K) * F(1:N,1:K-1) * A(I:M,1:K-1)**T
*                    * A(I:M,K).
*
         IF( K.GT.1 ) THEN
            CALL SGEMV( 'Transpose', M-I+1, K-1, -TAU( K ),
     $                  A( I, 1 ), LDA, A( I, K ), 1, ZERO,
     $                  AUXV( 1 ), 1 )
*
            CALL SGEMV( 'No transpose', N+NRHS, K-1, ONE,
     $                  F( 1, 1 ), LDF, AUXV( 1 ), 1, ONE,
     $                  F( 1, K ), 1 )
         END IF
*
*        ===============================================================
*
*        Update the current I-th row of A:
*        A(I,K+1:N+NRHS) := A(I,K+1:N+NRHS)
*                         - A(I,1:K)*F(K+1:N+NRHS,1:K)**T.
*
         IF( K.LT.N+NRHS ) THEN
            CALL SGEMV( 'No transpose', N+NRHS-K, K, -ONE,
     $                  F( K+1, 1 ), LDF, A( I, 1 ), LDA, ONE,
     $                  A( I, K+1 ), LDA )
         END IF
*
         A( I, K ) = AIK
*
*        Update the partial column 2-norms for the residual matrix,
*        only if the residual matrix A(I+1:M,K+1:N) exists, i.e.
*        when K < MINMNFACT = min( M-IOFFSET, N ).
*
         IF( K.LT.MINMNFACT ) THEN
*
            DO J = K + 1, N
               IF( VN1( J ).NE.ZERO ) THEN
*
*                 NOTE: The following lines follow from the analysis in
*                 Lapack Working Note 176.
*
                  TEMP = ABS( A( I, J ) ) / VN1( J )
                  TEMP = MAX( ZERO, ( ONE+TEMP )*( ONE-TEMP ) )
                  TEMP2 = TEMP*( VN1( J ) / VN2( J ) )**2
                  IF( TEMP2.LE.TOL3Z ) THEN
*
*                    At J-index, we have a difficult column for the
*                    update of the 2-norm. Save the index of the previous
*                    difficult column in IWORK(J-1).
*                    NOTE: ILSTCC > 1, threfore we can use IWORK only
*                    with N-1 elements, where the elements are
*                    shifted by 1 to the left.
*
                     IWORK( J-1 ) = LSTICC
*
*                    Set the index of the last difficult column LSTICC.
*
                     LSTICC = J
*
                  ELSE
                     VN1( J ) = VN1( J )*SQRT( TEMP )
                  END IF
               END IF
            END DO
*
         END IF
*
*        End of while loop.
*
      END DO
*
*     Now, afler the loop:
*        Set KB, the number of factorized columns in the block;
*        Set IF, the number of processed rows in the block, which
*                is the same as the number of processed rows in
*                the original whole matrix A_orig, IF = IOFFSET + KB.
*
      KB = K
      IF = I
*
*     Apply the block reflector to the residual of the matrix A
*     and the residual of the right hand sides B, if the residual
*     matrix and and/or the residual of the right hand sides
*     exist,  i.e. if the submatrix A(I+1:M,KB+1:N+NRHS) exists.
*     This occurs when KB < MINMNUPDT = min( M-IOFFSET, N+NRHS ):
*
*     A(IF+1:M,K+1:N+NRHS) := A(IF+1:M,KB+1:N+NRHS) -
*                         A(IF+1:M,1:KB) * F(KB+1:N+NRHS,1:KB)**T.
*
      IF( KB.LT.MINMNUPDT ) THEN
         CALL SGEMM( 'No transpose', 'Transpose',
     $         M-IF, N+NRHS-KB, KB, -ONE, A( IF+1, 1 ), LDA,
     $         F( KB+1, 1 ), LDF, ONE, A( IF+1, KB+1 ), LDA )
      END IF
*
*     Recompute the 2-norm of the difficult columns.
*     Loop over the index of the difficult columns from the largest
*     to the smallest index.
*
      DO WHILE( LSTICC.GT.0 )
*
*        LSTICC is the index of the last difficult column is greater
*        than 1.
*        ITEMP is the index of the previous difficult column.
*
         ITEMP = IWORK( LSTICC-1 )
*
*        Compute the 2-norm explicilty for the last difficult column and
*        save it in the partial and exact 2-norm vectors VN1 and VN2.
*
*        NOTE: The computation of VN1( LSTICC ) relies on the fact that
*        SNRM2 does not fail on vectors with norm below the value of
*        SQRT(SLAMCH('S'))
*
         VN1( LSTICC ) = SNRM2( M-IF, A( IF+1, LSTICC ), 1 )
         VN2( LSTICC ) = VN1( LSTICC )
*
*        Downdate the index of the last difficult column to
*        the index of the previous difficult column.
*
         LSTICC = ITEMP
*
      END DO
*
      RETURN
*
*     End of SLAQP3RK
*
      END