163
164
165
166
167
168 IMPLICIT NONE
169
170
171 CHARACTER SIDE, TRANS
172 INTEGER M, N, N1, N2, LDQ, LDC, LWORK, INFO
173
174
175 REAL Q( LDQ, * ), C( LDC, * ), WORK( * )
176
177
178
179
180
181 REAL ONE
182 parameter( one = 1.0e+0 )
183
184
185 LOGICAL LEFT, LQUERY, NOTRAN
186 INTEGER I, LDWORK, LEN, LWKOPT, NB, NQ, NW
187
188
189 LOGICAL LSAME
190 REAL SROUNDUP_LWORK
192
193
195
196
197 INTRINSIC max, min
198
199
200
201
202
203 info = 0
204 left =
lsame( side,
'L' )
205 notran =
lsame( trans,
'N' )
206 lquery = ( lwork.EQ.-1 )
207
208
209
210
211 IF( left ) THEN
212 nq = m
213 ELSE
214 nq = n
215 END IF
216 nw = nq
217 IF( n1.EQ.0 .OR. n2.EQ.0 ) nw = 1
218 IF( .NOT.left .AND. .NOT.
lsame( side,
'R' ) )
THEN
219 info = -1
220 ELSE IF( .NOT.
lsame( trans,
'N' ) .AND. .NOT.
lsame( trans,
'T' ) )
221 $ THEN
222 info = -2
223 ELSE IF( m.LT.0 ) THEN
224 info = -3
225 ELSE IF( n.LT.0 ) THEN
226 info = -4
227 ELSE IF( n1.LT.0 .OR. n1+n2.NE.nq ) THEN
228 info = -5
229 ELSE IF( n2.LT.0 ) THEN
230 info = -6
231 ELSE IF( ldq.LT.max( 1, nq ) ) THEN
232 info = -8
233 ELSE IF( ldc.LT.max( 1, m ) ) THEN
234 info = -10
235 ELSE IF( lwork.LT.nw .AND. .NOT.lquery ) THEN
236 info = -12
237 END IF
238
239 IF( info.EQ.0 ) THEN
240 lwkopt = m*n
242 END IF
243
244 IF( info.NE.0 ) THEN
245 CALL xerbla(
'SORM22', -info )
246 RETURN
247 ELSE IF( lquery ) THEN
248 RETURN
249 END IF
250
251
252
253 IF( m.EQ.0 .OR. n.EQ.0 ) THEN
254 work( 1 ) = 1
255 RETURN
256 END IF
257
258
259
260 IF( n1.EQ.0 ) THEN
261 CALL strmm( side,
'Upper', trans,
'Non-Unit', m, n, one,
262 $ q, ldq, c, ldc )
263 work( 1 ) = one
264 RETURN
265 ELSE IF( n2.EQ.0 ) THEN
266 CALL strmm( side,
'Lower', trans,
'Non-Unit', m, n, one,
267 $ q, ldq, c, ldc )
268 work( 1 ) = one
269 RETURN
270 END IF
271
272
273
274 nb = max( 1, min( lwork, lwkopt ) / nq )
275
276 IF( left ) THEN
277 IF( notran ) THEN
278 DO i = 1, n, nb
279 len = min( nb, n-i+1 )
280 ldwork = m
281
282
283
284 CALL slacpy(
'All', n1, len, c( n2+1, i ), ldc, work,
285 $ ldwork )
286 CALL strmm(
'Left',
'Lower',
'No Transpose',
'Non-Unit',
287 $ n1, len, one, q( 1, n2+1 ), ldq, work,
288 $ ldwork )
289
290
291
292 CALL sgemm(
'No Transpose',
'No Transpose', n1, len, n2,
293 $ one, q, ldq, c( 1, i ), ldc, one, work,
294 $ ldwork )
295
296
297
298 CALL slacpy(
'All', n2, len, c( 1, i ), ldc,
299 $ work( n1+1 ), ldwork )
300 CALL strmm(
'Left',
'Upper',
'No Transpose',
'Non-Unit',
301 $ n2, len, one, q( n1+1, 1 ), ldq,
302 $ work( n1+1 ), ldwork )
303
304
305
306 CALL sgemm(
'No Transpose',
'No Transpose', n2, len, n1,
307 $ one, q( n1+1, n2+1 ), ldq, c( n2+1, i ), ldc,
308 $ one, work( n1+1 ), ldwork )
309
310
311
312 CALL slacpy(
'All', m, len, work, ldwork, c( 1, i ),
313 $ ldc )
314 END DO
315 ELSE
316 DO i = 1, n, nb
317 len = min( nb, n-i+1 )
318 ldwork = m
319
320
321
322 CALL slacpy(
'All', n2, len, c( n1+1, i ), ldc, work,
323 $ ldwork )
324 CALL strmm(
'Left',
'Upper',
'Transpose',
'Non-Unit',
325 $ n2, len, one, q( n1+1, 1 ), ldq, work,
326 $ ldwork )
327
328
329
330 CALL sgemm(
'Transpose',
'No Transpose', n2, len, n1,
331 $ one, q, ldq, c( 1, i ), ldc, one, work,
332 $ ldwork )
333
334
335
336 CALL slacpy(
'All', n1, len, c( 1, i ), ldc,
337 $ work( n2+1 ), ldwork )
338 CALL strmm(
'Left',
'Lower',
'Transpose',
'Non-Unit',
339 $ n1, len, one, q( 1, n2+1 ), ldq,
340 $ work( n2+1 ), ldwork )
341
342
343
344 CALL sgemm(
'Transpose',
'No Transpose', n1, len, n2,
345 $ one, q( n1+1, n2+1 ), ldq, c( n1+1, i ), ldc,
346 $ one, work( n2+1 ), ldwork )
347
348
349
350 CALL slacpy(
'All', m, len, work, ldwork, c( 1, i ),
351 $ ldc )
352 END DO
353 END IF
354 ELSE
355 IF( notran ) THEN
356 DO i = 1, m, nb
357 len = min( nb, m-i+1 )
358 ldwork = len
359
360
361
362 CALL slacpy(
'All', len, n2, c( i, n1+1 ), ldc, work,
363 $ ldwork )
364 CALL strmm(
'Right',
'Upper',
'No Transpose',
'Non-Unit',
365 $ len, n2, one, q( n1+1, 1 ), ldq, work,
366 $ ldwork )
367
368
369
370 CALL sgemm(
'No Transpose',
'No Transpose', len, n2, n1,
371 $ one, c( i, 1 ), ldc, q, ldq, one, work,
372 $ ldwork )
373
374
375
376 CALL slacpy(
'All', len, n1, c( i, 1 ), ldc,
377 $ work( 1 + n2*ldwork ), ldwork )
378 CALL strmm(
'Right',
'Lower',
'No Transpose',
'Non-Unit',
379 $ len, n1, one, q( 1, n2+1 ), ldq,
380 $ work( 1 + n2*ldwork ), ldwork )
381
382
383
384 CALL sgemm(
'No Transpose',
'No Transpose', len, n1, n2,
385 $ one, c( i, n1+1 ), ldc, q( n1+1, n2+1 ), ldq,
386 $ one, work( 1 + n2*ldwork ), ldwork )
387
388
389
390 CALL slacpy(
'All', len, n, work, ldwork, c( i, 1 ),
391 $ ldc )
392 END DO
393 ELSE
394 DO i = 1, m, nb
395 len = min( nb, m-i+1 )
396 ldwork = len
397
398
399
400 CALL slacpy(
'All', len, n1, c( i, n2+1 ), ldc, work,
401 $ ldwork )
402 CALL strmm(
'Right',
'Lower',
'Transpose',
'Non-Unit',
403 $ len, n1, one, q( 1, n2+1 ), ldq, work,
404 $ ldwork )
405
406
407
408 CALL sgemm(
'No Transpose',
'Transpose', len, n1, n2,
409 $ one, c( i, 1 ), ldc, q, ldq, one, work,
410 $ ldwork )
411
412
413
414 CALL slacpy(
'All', len, n2, c( i, 1 ), ldc,
415 $ work( 1 + n1*ldwork ), ldwork )
416 CALL strmm(
'Right',
'Upper',
'Transpose',
'Non-Unit',
417 $ len, n2, one, q( n1+1, 1 ), ldq,
418 $ work( 1 + n1*ldwork ), ldwork )
419
420
421
422 CALL sgemm(
'No Transpose',
'Transpose', len, n2, n1,
423 $ one, c( i, n2+1 ), ldc, q( n1+1, n2+1 ), ldq,
424 $ one, work( 1 + n1*ldwork ), ldwork )
425
426
427
428 CALL slacpy(
'All', len, n, work, ldwork, c( i, 1 ),
429 $ ldc )
430 END DO
431 END IF
432 END IF
433
435 RETURN
436
437
438
subroutine xerbla(srname, info)
subroutine sgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
SGEMM
subroutine slacpy(uplo, m, n, a, lda, b, ldb)
SLACPY copies all or part of one two-dimensional array to another.
logical function lsame(ca, cb)
LSAME
real function sroundup_lwork(lwork)
SROUNDUP_LWORK
subroutine strmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
STRMM