| | 408 | |
| | 409 | |
| | 410 | /** |
| | 411 | * Compute the inverse of a triangular matrix. |
| | 412 | * @param Uplo whether the matrix is upper of lower triangular |
| | 413 | * @param Diag whether the matrix if unit diagonal |
| | 414 | * |
| | 415 | */ |
| | 416 | template<class Field> |
| | 417 | static void |
| | 418 | ftrtri (const Field& F, const FFLAS_UPLO Uplo, const FFLAS_DIAG Diag, |
| | 419 | const size_t N, typename Field::Element * A, const size_t lda){ |
| | 420 | |
| | 421 | typename Field::Element mone, one; |
| | 422 | F.init(one,1.0); |
| | 423 | F.init(mone,-1.0); |
| | 424 | if ((N == 1) && (Diag == FflasNonUnit)) |
| | 425 | F.divin (*A); |
| | 426 | else{ |
| | 427 | size_t N1 = N/2; |
| | 428 | size_t N2 = N - N1; |
| | 429 | ftrtri (F, Uplo, Diag, N1, A, lda); |
| | 430 | ftrtri (F, Uplo, Diag, N2, A + N1*(lda+1), lda); |
| | 431 | if (Uplo == FflasUpper){ |
| | 432 | ftrmm (F, FflasLeft, Uplo, FflasNoTrans, Diag, N1, N2, |
| | 433 | one, A, lda, A + N1, lda); |
| | 434 | ftrmm (F, FflasRight, Uplo, FflasNoTrans, Diag, N1, N2, |
| | 435 | mone, A + N1*(lda+1), lda, A + N1, lda); |
| | 436 | } else { |
| | 437 | ftrmm (F, FflasLeft, Uplo, FflasNoTrans, Diag, N2, N1, |
| | 438 | one, A + N1*(lda+1), lda, A + N1*lda, lda); |
| | 439 | ftrmm (F, FflasRight, Uplo, FflasNoTrans, Diag, N2, N1, |
| | 440 | mone, A, lda, A + N1*lda, lda); |
| | 441 | } |
| | 442 | } |
| | 443 | } |
| | 444 | |
| | 445 | |
| | 446 | /** |
| | 447 | * Compute the product UL of the upper, resp lower triangular matrices U and L |
| | 448 | * stored one above the other in the square matrix A. |
| | 449 | * The matrix U is supposed to be unit diagonal |
| | 450 | * |
| | 451 | */ |
| | 452 | template<class Field> |
| | 453 | static void |
| | 454 | ftrtrm (const Field& F, const size_t N, typename Field::Element * A, const size_t lda){ |
| | 455 | |
| | 456 | typename Field::Element one; |
| | 457 | F.init(one,1.0); |
| | 458 | |
| | 459 | if (N == 1) |
| | 460 | return; |
| | 461 | size_t N1 = N/2; |
| | 462 | size_t N2 = N-N1; |
| | 463 | |
| | 464 | ftrtrm (F, N1, A, lda); |
| | 465 | |
| | 466 | fgemm (F, FflasNoTrans, FflasNoTrans, N1, N1, N2, one, |
| | 467 | A+N1, lda, A+N1*lda, lda, one, A, lda); |
| | 468 | |
| | 469 | ftrmm (F, FflasRight, FflasLower, N1, N2, one, A + N1*(lda+1), lda, A + N1, lda); |
| | 470 | |
| | 471 | ftrmm (F, FflasLeft, FflasUpper, N2, N1, one, A + N1*(lda+1), lda, A + N1*lda, lda); |
| | 472 | |
| | 473 | ftrtrm (F, N2, A + N1*(lda+1), lda); |
| | 474 | |
| | 475 | } |
| | 476 | |
| | 477 | /** |
| | 478 | * Compute the Column Echelon form of the input matrix in-place. |
| | 479 | * |
| | 480 | * After the computation A = [ M \ V ] such that AU = C is a column echelon |
| | 481 | * decomposition of A, with U = P^T [ V ] and C = M + Q [ Ir ] |
| | 482 | * [ 0 In-r ] [ 0 ] |
| | 483 | */ |
| | 484 | template <class Field> |
| | 485 | static size_t |
| | 486 | ColumnEchelonForm (const Field& F, const size_t M, const size_t N, |
| | 487 | typename Field::Element * A, const size_t lda, |
| | 488 | size_t* P, size_t* Q){ |
| | 489 | |
| | 490 | typename Field::Element one, mone; |
| | 491 | F.init (one, 1.0); |
| | 492 | F.neg (mone, one); |
| | 493 | size_t r; |
| | 494 | |
| | 495 | r = LUdivine (F, FflasUnit, M, N, A, lda, P, Q); |
| | 496 | |
| | 497 | ftrtri (F, FflasUpper, FflasUnit, r, A, lda); |
| | 498 | |
| | 499 | ftrmm (F, FflasLeft, FflasUpper, FflasNoTrans, FflasUnit, r, N, |
| | 500 | mone, A, lda, A+r, lda); |
| | 501 | |
| | 502 | return r; |
| | 503 | |
| | 504 | } |
| | 505 | |
| | 506 | /** |
| | 507 | * Compute the Reduced Column Echelon form of the input matrix in-place. |
| | 508 | * |
| | 509 | * After the computation A = [ V ] such that AU = R is a reduced column echelon |
| | 510 | * [ M 0 ] |
| | 511 | * decomposition of A, where U = P^T [ V ] and R = Q [ Ir ] |
| | 512 | * [ 0 In-r ] [ M 0 ] |
| | 513 | */ |
| | 514 | |
| | 515 | template <class Field> |
| | 516 | static size_t |
| | 517 | ReducedColumnEchelonForm (const Field& F, const size_t M, const size_t N, |
| | 518 | typename Field::Element * A, const size_t lda, |
| | 519 | size_t* P, size_t* Q){ |
| | 520 | |
| | 521 | typename Field::Element one, mone; |
| | 522 | F.init (one, 1.0); |
| | 523 | F.neg (mone, one); |
| | 524 | size_t r; |
| | 525 | |
| | 526 | r = ColumnEchelonForm (F, M, N, A, lda, P, Q); |
| | 527 | |
| | 528 | // M = Q^T M |
| | 529 | for (int i=r-1; i>=0; --i){ |
| | 530 | if ( Q[i]> (size_t) i ){ |
| | 531 | fswap( F, i, |
| | 532 | A + Q[i]*lda, 1, |
| | 533 | A + i*lda, 1 ); |
| | 534 | } |
| | 535 | } |
| | 536 | |
| | 537 | ftrtri (F, FflasLower, FflasNonUnit, r, A, lda); |
| | 538 | |
| | 539 | ftrmm (F, FflasRight, FflasLower, FflasNoTrans, FflasNonUnit, r, N, |
| | 540 | one, A, lda, A+r, lda); |
| | 541 | |
| | 542 | ftrtrm (F, r, A, lda); |
| | 543 | |
| | 544 | return r; |
| | 545 | |
| | 546 | } |
| | 547 | |