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