1*> \brief \b SPFTRF
2*
3*  =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6*            http://www.netlib.org/lapack/explore-html/
7*
8*> \htmlonly
9*> Download SPFTRF + dependencies
10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/spftrf.f">
11*> [TGZ]</a>
12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/spftrf.f">
13*> [ZIP]</a>
14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/spftrf.f">
15*> [TXT]</a>
16*> \endhtmlonly
17*
18*  Definition:
19*  ===========
20*
21*       SUBROUTINE SPFTRF( TRANSR, UPLO, N, A, INFO )
22*
23*       .. Scalar Arguments ..
24*       CHARACTER          TRANSR, UPLO
25*       INTEGER            N, INFO
26*       ..
27*       .. Array Arguments ..
28*       REAL               A( 0: * )
29*
30*
31*> \par Purpose:
32*  =============
33*>
34*> \verbatim
35*>
36*> SPFTRF computes the Cholesky factorization of a real symmetric
37*> positive definite matrix A.
38*>
39*> The factorization has the form
40*>    A = U**T * U,  if UPLO = 'U', or
41*>    A = L  * L**T,  if UPLO = 'L',
42*> where U is an upper triangular matrix and L is lower triangular.
43*>
44*> This is the block version of the algorithm, calling Level 3 BLAS.
45*> \endverbatim
46*
47*  Arguments:
48*  ==========
49*
50*> \param[in] TRANSR
51*> \verbatim
52*>          TRANSR is CHARACTER*1
53*>          = 'N':  The Normal TRANSR of RFP A is stored;
54*>          = 'T':  The Transpose TRANSR of RFP A is stored.
55*> \endverbatim
56*>
57*> \param[in] UPLO
58*> \verbatim
59*>          UPLO is CHARACTER*1
60*>          = 'U':  Upper triangle of RFP A is stored;
61*>          = 'L':  Lower triangle of RFP A is stored.
62*> \endverbatim
63*>
64*> \param[in] N
65*> \verbatim
66*>          N is INTEGER
67*>          The order of the matrix A.  N >= 0.
68*> \endverbatim
69*>
70*> \param[in,out] A
71*> \verbatim
72*>          A is REAL array, dimension ( N*(N+1)/2 );
73*>          On entry, the symmetric matrix A in RFP format. RFP format is
74*>          described by TRANSR, UPLO, and N as follows: If TRANSR = 'N'
75*>          then RFP A is (0:N,0:k-1) when N is even; k=N/2. RFP A is
76*>          (0:N-1,0:k) when N is odd; k=N/2. IF TRANSR = 'T' then RFP is
77*>          the transpose of RFP A as defined when
78*>          TRANSR = 'N'. The contents of RFP A are defined by UPLO as
79*>          follows: If UPLO = 'U' the RFP A contains the NT elements of
80*>          upper packed A. If UPLO = 'L' the RFP A contains the elements
81*>          of lower packed A. The LDA of RFP A is (N+1)/2 when TRANSR =
82*>          'T'. When TRANSR is 'N' the LDA is N+1 when N is even and N
83*>          is odd. See the Note below for more details.
84*>
85*>          On exit, if INFO = 0, the factor U or L from the Cholesky
86*>          factorization RFP A = U**T*U or RFP A = L*L**T.
87*> \endverbatim
88*>
89*> \param[out] INFO
90*> \verbatim
91*>          INFO is INTEGER
92*>          = 0:  successful exit
93*>          < 0:  if INFO = -i, the i-th argument had an illegal value
94*>          > 0:  if INFO = i, the leading minor of order i is not
95*>                positive definite, and the factorization could not be
96*>                completed.
97*> \endverbatim
98*
99*  Authors:
100*  ========
101*
102*> \author Univ. of Tennessee
103*> \author Univ. of California Berkeley
104*> \author Univ. of Colorado Denver
105*> \author NAG Ltd.
106*
107*> \date December 2016
108*
109*> \ingroup realOTHERcomputational
110*
111*> \par Further Details:
112*  =====================
113*>
114*> \verbatim
115*>
116*>  We first consider Rectangular Full Packed (RFP) Format when N is
117*>  even. We give an example where N = 6.
118*>
119*>      AP is Upper             AP is Lower
120*>
121*>   00 01 02 03 04 05       00
122*>      11 12 13 14 15       10 11
123*>         22 23 24 25       20 21 22
124*>            33 34 35       30 31 32 33
125*>               44 45       40 41 42 43 44
126*>                  55       50 51 52 53 54 55
127*>
128*>
129*>  Let TRANSR = 'N'. RFP holds AP as follows:
130*>  For UPLO = 'U' the upper trapezoid A(0:5,0:2) consists of the last
131*>  three columns of AP upper. The lower triangle A(4:6,0:2) consists of
132*>  the transpose of the first three columns of AP upper.
133*>  For UPLO = 'L' the lower trapezoid A(1:6,0:2) consists of the first
134*>  three columns of AP lower. The upper triangle A(0:2,0:2) consists of
135*>  the transpose of the last three columns of AP lower.
136*>  This covers the case N even and TRANSR = 'N'.
137*>
138*>         RFP A                   RFP A
139*>
140*>        03 04 05                33 43 53
141*>        13 14 15                00 44 54
142*>        23 24 25                10 11 55
143*>        33 34 35                20 21 22
144*>        00 44 45                30 31 32
145*>        01 11 55                40 41 42
146*>        02 12 22                50 51 52
147*>
148*>  Now let TRANSR = 'T'. RFP A in both UPLO cases is just the
149*>  transpose of RFP A above. One therefore gets:
150*>
151*>
152*>           RFP A                   RFP A
153*>
154*>     03 13 23 33 00 01 02    33 00 10 20 30 40 50
155*>     04 14 24 34 44 11 12    43 44 11 21 31 41 51
156*>     05 15 25 35 45 55 22    53 54 55 22 32 42 52
157*>
158*>
159*>  We then consider Rectangular Full Packed (RFP) Format when N is
160*>  odd. We give an example where N = 5.
161*>
162*>     AP is Upper                 AP is Lower
163*>
164*>   00 01 02 03 04              00
165*>      11 12 13 14              10 11
166*>         22 23 24              20 21 22
167*>            33 34              30 31 32 33
168*>               44              40 41 42 43 44
169*>
170*>
171*>  Let TRANSR = 'N'. RFP holds AP as follows:
172*>  For UPLO = 'U' the upper trapezoid A(0:4,0:2) consists of the last
173*>  three columns of AP upper. The lower triangle A(3:4,0:1) consists of
174*>  the transpose of the first two columns of AP upper.
175*>  For UPLO = 'L' the lower trapezoid A(0:4,0:2) consists of the first
176*>  three columns of AP lower. The upper triangle A(0:1,1:2) consists of
177*>  the transpose of the last two columns of AP lower.
178*>  This covers the case N odd and TRANSR = 'N'.
179*>
180*>         RFP A                   RFP A
181*>
182*>        02 03 04                00 33 43
183*>        12 13 14                10 11 44
184*>        22 23 24                20 21 22
185*>        00 33 34                30 31 32
186*>        01 11 44                40 41 42
187*>
188*>  Now let TRANSR = 'T'. RFP A in both UPLO cases is just the
189*>  transpose of RFP A above. One therefore gets:
190*>
191*>           RFP A                   RFP A
192*>
193*>     02 12 22 00 01             00 10 20 30 40 50
194*>     03 13 23 33 11             33 11 21 31 41 51
195*>     04 14 24 34 44             43 44 22 32 42 52
196*> \endverbatim
197*>
198*  =====================================================================
199      SUBROUTINE SPFTRF( TRANSR, UPLO, N, A, INFO )
200*
201*  -- LAPACK computational routine (version 3.7.0) --
202*  -- LAPACK is a software package provided by Univ. of Tennessee,    --
203*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
204*     December 2016
205*
206*     .. Scalar Arguments ..
207      CHARACTER          TRANSR, UPLO
208      INTEGER            N, INFO
209*     ..
210*     .. Array Arguments ..
211      REAL               A( 0: * )
212*
213*  =====================================================================
214*
215*     .. Parameters ..
216      REAL               ONE
217      PARAMETER          ( ONE = 1.0E+0 )
218*     ..
219*     .. Local Scalars ..
220      LOGICAL            LOWER, NISODD, NORMALTRANSR
221      INTEGER            N1, N2, K
222*     ..
223*     .. External Functions ..
224      LOGICAL            LSAME
225      EXTERNAL           LSAME
226*     ..
227*     .. External Subroutines ..
228      EXTERNAL           XERBLA, SSYRK, SPOTRF, STRSM
229*     ..
230*     .. Intrinsic Functions ..
231      INTRINSIC          MOD
232*     ..
233*     .. Executable Statements ..
234*
235*     Test the input parameters.
236*
237      INFO = 0
238      NORMALTRANSR = LSAME( TRANSR, 'N' )
239      LOWER = LSAME( UPLO, 'L' )
240      IF( .NOT.NORMALTRANSR .AND. .NOT.LSAME( TRANSR, 'T' ) ) THEN
241         INFO = -1
242      ELSE IF( .NOT.LOWER .AND. .NOT.LSAME( UPLO, 'U' ) ) THEN
243         INFO = -2
244      ELSE IF( N.LT.0 ) THEN
245         INFO = -3
246      END IF
247      IF( INFO.NE.0 ) THEN
248         CALL XERBLA( 'SPFTRF', -INFO )
249         RETURN
250      END IF
251*
252*     Quick return if possible
253*
254      IF( N.EQ.0 )
255     $   RETURN
256*
257*     If N is odd, set NISODD = .TRUE.
258*     If N is even, set K = N/2 and NISODD = .FALSE.
259*
260      IF( MOD( N, 2 ).EQ.0 ) THEN
261         K = N / 2
262         NISODD = .FALSE.
263      ELSE
264         NISODD = .TRUE.
265      END IF
266*
267*     Set N1 and N2 depending on LOWER
268*
269      IF( LOWER ) THEN
270         N2 = N / 2
271         N1 = N - N2
272      ELSE
273         N1 = N / 2
274         N2 = N - N1
275      END IF
276*
277*     start execution: there are eight cases
278*
279      IF( NISODD ) THEN
280*
281*        N is odd
282*
283         IF( NORMALTRANSR ) THEN
284*
285*           N is odd and TRANSR = 'N'
286*
287            IF( LOWER ) THEN
288*
289*             SRPA for LOWER, NORMAL and N is odd ( a(0:n-1,0:n1-1) )
290*             T1 -> a(0,0), T2 -> a(0,1), S -> a(n1,0)
291*             T1 -> a(0), T2 -> a(n), S -> a(n1)
292*
293               CALL SPOTRF( 'L', N1, A( 0 ), N, INFO )
294               IF( INFO.GT.0 )
295     $            RETURN
296               CALL STRSM( 'R', 'L', 'T', 'N', N2, N1, ONE, A( 0 ), N,
297     $                     A( N1 ), N )
298               CALL SSYRK( 'U', 'N', N2, N1, -ONE, A( N1 ), N, ONE,
299     $                     A( N ), N )
300               CALL SPOTRF( 'U', N2, A( N ), N, INFO )
301               IF( INFO.GT.0 )
302     $            INFO = INFO + N1
303*
304            ELSE
305*
306*             SRPA for UPPER, NORMAL and N is odd ( a(0:n-1,0:n2-1)
307*             T1 -> a(n1+1,0), T2 -> a(n1,0), S -> a(0,0)
308*             T1 -> a(n2), T2 -> a(n1), S -> a(0)
309*
310               CALL SPOTRF( 'L', N1, A( N2 ), N, INFO )
311               IF( INFO.GT.0 )
312     $            RETURN
313               CALL STRSM( 'L', 'L', 'N', 'N', N1, N2, ONE, A( N2 ), N,
314     $                     A( 0 ), N )
315               CALL SSYRK( 'U', 'T', N2, N1, -ONE, A( 0 ), N, ONE,
316     $                     A( N1 ), N )
317               CALL SPOTRF( 'U', N2, A( N1 ), N, INFO )
318               IF( INFO.GT.0 )
319     $            INFO = INFO + N1
320*
321            END IF
322*
323         ELSE
324*
325*           N is odd and TRANSR = 'T'
326*
327            IF( LOWER ) THEN
328*
329*              SRPA for LOWER, TRANSPOSE and N is odd
330*              T1 -> A(0,0) , T2 -> A(1,0) , S -> A(0,n1)
331*              T1 -> a(0+0) , T2 -> a(1+0) , S -> a(0+n1*n1); lda=n1
332*
333               CALL SPOTRF( 'U', N1, A( 0 ), N1, INFO )
334               IF( INFO.GT.0 )
335     $            RETURN
336               CALL STRSM( 'L', 'U', 'T', 'N', N1, N2, ONE, A( 0 ), N1,
337     $                     A( N1*N1 ), N1 )
338               CALL SSYRK( 'L', 'T', N2, N1, -ONE, A( N1*N1 ), N1, ONE,
339     $                     A( 1 ), N1 )
340               CALL SPOTRF( 'L', N2, A( 1 ), N1, INFO )
341               IF( INFO.GT.0 )
342     $            INFO = INFO + N1
343*
344            ELSE
345*
346*              SRPA for UPPER, TRANSPOSE and N is odd
347*              T1 -> A(0,n1+1), T2 -> A(0,n1), S -> A(0,0)
348*              T1 -> a(n2*n2), T2 -> a(n1*n2), S -> a(0); lda = n2
349*
350               CALL SPOTRF( 'U', N1, A( N2*N2 ), N2, INFO )
351               IF( INFO.GT.0 )
352     $            RETURN
353               CALL STRSM( 'R', 'U', 'N', 'N', N2, N1, ONE, A( N2*N2 ),
354     $                     N2, A( 0 ), N2 )
355               CALL SSYRK( 'L', 'N', N2, N1, -ONE, A( 0 ), N2, ONE,
356     $                     A( N1*N2 ), N2 )
357               CALL SPOTRF( 'L', N2, A( N1*N2 ), N2, INFO )
358               IF( INFO.GT.0 )
359     $            INFO = INFO + N1
360*
361            END IF
362*
363         END IF
364*
365      ELSE
366*
367*        N is even
368*
369         IF( NORMALTRANSR ) THEN
370*
371*           N is even and TRANSR = 'N'
372*
373            IF( LOWER ) THEN
374*
375*              SRPA for LOWER, NORMAL, and N is even ( a(0:n,0:k-1) )
376*              T1 -> a(1,0), T2 -> a(0,0), S -> a(k+1,0)
377*              T1 -> a(1), T2 -> a(0), S -> a(k+1)
378*
379               CALL SPOTRF( 'L', K, A( 1 ), N+1, INFO )
380               IF( INFO.GT.0 )
381     $            RETURN
382               CALL STRSM( 'R', 'L', 'T', 'N', K, K, ONE, A( 1 ), N+1,
383     $                     A( K+1 ), N+1 )
384               CALL SSYRK( 'U', 'N', K, K, -ONE, A( K+1 ), N+1, ONE,
385     $                     A( 0 ), N+1 )
386               CALL SPOTRF( 'U', K, A( 0 ), N+1, INFO )
387               IF( INFO.GT.0 )
388     $            INFO = INFO + K
389*
390            ELSE
391*
392*              SRPA for UPPER, NORMAL, and N is even ( a(0:n,0:k-1) )
393*              T1 -> a(k+1,0) ,  T2 -> a(k,0),   S -> a(0,0)
394*              T1 -> a(k+1), T2 -> a(k), S -> a(0)
395*
396               CALL SPOTRF( 'L', K, A( K+1 ), N+1, INFO )
397               IF( INFO.GT.0 )
398     $            RETURN
399               CALL STRSM( 'L', 'L', 'N', 'N', K, K, ONE, A( K+1 ),
400     $                     N+1, A( 0 ), N+1 )
401               CALL SSYRK( 'U', 'T', K, K, -ONE, A( 0 ), N+1, ONE,
402     $                     A( K ), N+1 )
403               CALL SPOTRF( 'U', K, A( K ), N+1, INFO )
404               IF( INFO.GT.0 )
405     $            INFO = INFO + K
406*
407            END IF
408*
409         ELSE
410*
411*           N is even and TRANSR = 'T'
412*
413            IF( LOWER ) THEN
414*
415*              SRPA for LOWER, TRANSPOSE and N is even (see paper)
416*              T1 -> B(0,1), T2 -> B(0,0), S -> B(0,k+1)
417*              T1 -> a(0+k), T2 -> a(0+0), S -> a(0+k*(k+1)); lda=k
418*
419               CALL SPOTRF( 'U', K, A( 0+K ), K, INFO )
420               IF( INFO.GT.0 )
421     $            RETURN
422               CALL STRSM( 'L', 'U', 'T', 'N', K, K, ONE, A( K ), N1,
423     $                     A( K*( K+1 ) ), K )
424               CALL SSYRK( 'L', 'T', K, K, -ONE, A( K*( K+1 ) ), K, ONE,
425     $                     A( 0 ), K )
426               CALL SPOTRF( 'L', K, A( 0 ), K, INFO )
427               IF( INFO.GT.0 )
428     $            INFO = INFO + K
429*
430            ELSE
431*
432*              SRPA for UPPER, TRANSPOSE and N is even (see paper)
433*              T1 -> B(0,k+1),     T2 -> B(0,k),   S -> B(0,0)
434*              T1 -> a(0+k*(k+1)), T2 -> a(0+k*k), S -> a(0+0)); lda=k
435*
436               CALL SPOTRF( 'U', K, A( K*( K+1 ) ), K, INFO )
437               IF( INFO.GT.0 )
438     $            RETURN
439               CALL STRSM( 'R', 'U', 'N', 'N', K, K, ONE,
440     $                     A( K*( K+1 ) ), K, A( 0 ), K )
441               CALL SSYRK( 'L', 'N', K, K, -ONE, A( 0 ), K, ONE,
442     $                     A( K*K ), K )
443               CALL SPOTRF( 'L', K, A( K*K ), K, INFO )
444               IF( INFO.GT.0 )
445     $            INFO = INFO + K
446*
447            END IF
448*
449         END IF
450*
451      END IF
452*
453      RETURN
454*
455*     End of SPFTRF
456*
457      END
458