gonum.org/v1/gonum@v0.14.0/lapack/testlapack/locallapack.go (about) 1 // Copyright ©2020 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package testlapack 6 7 import ( 8 "math" 9 10 "gonum.org/v1/gonum/blas" 11 "gonum.org/v1/gonum/internal/asm/f64" 12 "gonum.org/v1/gonum/lapack" 13 ) 14 15 // dlagtm is a local implementation of Dlagtm to keep code paths independent. 16 func dlagtm(trans blas.Transpose, m, n int, alpha float64, dl, d, du []float64, b []float64, ldb int, beta float64, c []float64, ldc int) { 17 if m == 0 || n == 0 { 18 return 19 } 20 21 if beta != 1 { 22 if beta == 0 { 23 for i := 0; i < m; i++ { 24 ci := c[i*ldc : i*ldc+n] 25 for j := range ci { 26 ci[j] = 0 27 } 28 } 29 } else { 30 for i := 0; i < m; i++ { 31 ci := c[i*ldc : i*ldc+n] 32 for j := range ci { 33 ci[j] *= beta 34 } 35 } 36 } 37 } 38 39 if alpha == 0 { 40 return 41 } 42 43 if m == 1 { 44 if alpha == 1 { 45 for j := 0; j < n; j++ { 46 c[j] += d[0] * b[j] 47 } 48 } else { 49 for j := 0; j < n; j++ { 50 c[j] += alpha * d[0] * b[j] 51 } 52 } 53 return 54 } 55 56 if trans != blas.NoTrans { 57 dl, du = du, dl 58 } 59 60 if alpha == 1 { 61 for j := 0; j < n; j++ { 62 c[j] += d[0]*b[j] + du[0]*b[ldb+j] 63 } 64 for i := 1; i < m-1; i++ { 65 for j := 0; j < n; j++ { 66 c[i*ldc+j] += dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j] 67 } 68 } 69 for j := 0; j < n; j++ { 70 c[(m-1)*ldc+j] += dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j] 71 } 72 } else { 73 for j := 0; j < n; j++ { 74 c[j] += alpha * (d[0]*b[j] + du[0]*b[ldb+j]) 75 } 76 for i := 1; i < m-1; i++ { 77 for j := 0; j < n; j++ { 78 c[i*ldc+j] += alpha * (dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j]) 79 } 80 } 81 for j := 0; j < n; j++ { 82 c[(m-1)*ldc+j] += alpha * (dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j]) 83 } 84 } 85 } 86 87 // dlangt is a local implementation of Dlangt to keep code paths independent. 88 func dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 { 89 if n == 0 { 90 return 0 91 } 92 93 dl = dl[:n-1] 94 d = d[:n] 95 du = du[:n-1] 96 97 var anorm float64 98 switch norm { 99 case lapack.MaxAbs: 100 for _, diag := range [][]float64{dl, d, du} { 101 for _, di := range diag { 102 if math.IsNaN(di) { 103 return di 104 } 105 di = math.Abs(di) 106 if di > anorm { 107 anorm = di 108 } 109 } 110 } 111 case lapack.MaxColumnSum: 112 if n == 1 { 113 return math.Abs(d[0]) 114 } 115 anorm = math.Abs(d[0]) + math.Abs(dl[0]) 116 if math.IsNaN(anorm) { 117 return anorm 118 } 119 tmp := math.Abs(du[n-2]) + math.Abs(d[n-1]) 120 if math.IsNaN(tmp) { 121 return tmp 122 } 123 if tmp > anorm { 124 anorm = tmp 125 } 126 for i := 1; i < n-1; i++ { 127 tmp = math.Abs(du[i-1]) + math.Abs(d[i]) + math.Abs(dl[i]) 128 if math.IsNaN(tmp) { 129 return tmp 130 } 131 if tmp > anorm { 132 anorm = tmp 133 } 134 } 135 case lapack.MaxRowSum: 136 if n == 1 { 137 return math.Abs(d[0]) 138 } 139 anorm = math.Abs(d[0]) + math.Abs(du[0]) 140 if math.IsNaN(anorm) { 141 return anorm 142 } 143 tmp := math.Abs(dl[n-2]) + math.Abs(d[n-1]) 144 if math.IsNaN(tmp) { 145 return tmp 146 } 147 if tmp > anorm { 148 anorm = tmp 149 } 150 for i := 1; i < n-1; i++ { 151 tmp = math.Abs(dl[i-1]) + math.Abs(d[i]) + math.Abs(du[i]) 152 if math.IsNaN(tmp) { 153 return tmp 154 } 155 if tmp > anorm { 156 anorm = tmp 157 } 158 } 159 case lapack.Frobenius: 160 panic("not implemented") 161 default: 162 panic("invalid norm") 163 } 164 return anorm 165 } 166 167 // dlansy is a local implementation of Dlansy to keep code paths independent. 168 func dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int) float64 { 169 if n == 0 { 170 return 0 171 } 172 work := make([]float64, n) 173 switch norm { 174 case lapack.MaxAbs: 175 if uplo == blas.Upper { 176 var max float64 177 for i := 0; i < n; i++ { 178 for j := i; j < n; j++ { 179 v := math.Abs(a[i*lda+j]) 180 if math.IsNaN(v) { 181 return math.NaN() 182 } 183 if v > max { 184 max = v 185 } 186 } 187 } 188 return max 189 } 190 var max float64 191 for i := 0; i < n; i++ { 192 for j := 0; j <= i; j++ { 193 v := math.Abs(a[i*lda+j]) 194 if math.IsNaN(v) { 195 return math.NaN() 196 } 197 if v > max { 198 max = v 199 } 200 } 201 } 202 return max 203 case lapack.MaxRowSum, lapack.MaxColumnSum: 204 // A symmetric matrix has the same 1-norm and ∞-norm. 205 for i := 0; i < n; i++ { 206 work[i] = 0 207 } 208 if uplo == blas.Upper { 209 for i := 0; i < n; i++ { 210 work[i] += math.Abs(a[i*lda+i]) 211 for j := i + 1; j < n; j++ { 212 v := math.Abs(a[i*lda+j]) 213 work[i] += v 214 work[j] += v 215 } 216 } 217 } else { 218 for i := 0; i < n; i++ { 219 for j := 0; j < i; j++ { 220 v := math.Abs(a[i*lda+j]) 221 work[i] += v 222 work[j] += v 223 } 224 work[i] += math.Abs(a[i*lda+i]) 225 } 226 } 227 var max float64 228 for i := 0; i < n; i++ { 229 v := work[i] 230 if math.IsNaN(v) { 231 return math.NaN() 232 } 233 if v > max { 234 max = v 235 } 236 } 237 return max 238 case lapack.Frobenius: 239 panic("not implemented") 240 default: 241 panic("invalid norm") 242 } 243 } 244 245 // dlange is a local implementation of Dlange to keep code paths independent. 246 func dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int) float64 { 247 if m == 0 || n == 0 { 248 return 0 249 } 250 var value float64 251 switch norm { 252 case lapack.MaxAbs: 253 for i := 0; i < m; i++ { 254 for j := 0; j < n; j++ { 255 value = math.Max(value, math.Abs(a[i*lda+j])) 256 } 257 } 258 case lapack.MaxColumnSum: 259 work := make([]float64, n) 260 for i := 0; i < m; i++ { 261 for j := 0; j < n; j++ { 262 work[j] += math.Abs(a[i*lda+j]) 263 } 264 } 265 for i := 0; i < n; i++ { 266 value = math.Max(value, work[i]) 267 } 268 case lapack.MaxRowSum: 269 for i := 0; i < m; i++ { 270 var sum float64 271 for j := 0; j < n; j++ { 272 sum += math.Abs(a[i*lda+j]) 273 } 274 value = math.Max(value, sum) 275 } 276 case lapack.Frobenius: 277 for i := 0; i < m; i++ { 278 row := f64.L2NormUnitary(a[i*lda : i*lda+n]) 279 value = math.Hypot(value, row) 280 } 281 default: 282 panic("invalid norm") 283 } 284 return value 285 } 286 287 // dlansb is a local implementation of Dlansb to keep code paths independent. 288 func dlansb(norm lapack.MatrixNorm, uplo blas.Uplo, n, kd int, ab []float64, ldab int, work []float64) float64 { 289 if n == 0 { 290 return 0 291 } 292 var value float64 293 switch norm { 294 case lapack.MaxAbs: 295 if uplo == blas.Upper { 296 for i := 0; i < n; i++ { 297 for j := 0; j < min(n-i, kd+1); j++ { 298 aij := math.Abs(ab[i*ldab+j]) 299 if aij > value || math.IsNaN(aij) { 300 value = aij 301 } 302 } 303 } 304 } else { 305 for i := 0; i < n; i++ { 306 for j := max(0, kd-i); j < kd+1; j++ { 307 aij := math.Abs(ab[i*ldab+j]) 308 if aij > value || math.IsNaN(aij) { 309 value = aij 310 } 311 } 312 } 313 } 314 case lapack.MaxColumnSum, lapack.MaxRowSum: 315 work = work[:n] 316 var sum float64 317 if uplo == blas.Upper { 318 for i := range work { 319 work[i] = 0 320 } 321 for i := 0; i < n; i++ { 322 sum := work[i] + math.Abs(ab[i*ldab]) 323 for j := i + 1; j < min(i+kd+1, n); j++ { 324 aij := math.Abs(ab[i*ldab+j-i]) 325 sum += aij 326 work[j] += aij 327 } 328 if sum > value || math.IsNaN(sum) { 329 value = sum 330 } 331 } 332 } else { 333 for i := 0; i < n; i++ { 334 sum = 0 335 for j := max(0, i-kd); j < i; j++ { 336 aij := math.Abs(ab[i*ldab+kd+j-i]) 337 sum += aij 338 work[j] += aij 339 } 340 work[i] = sum + math.Abs(ab[i*ldab+kd]) 341 } 342 for _, sum := range work { 343 if sum > value || math.IsNaN(sum) { 344 value = sum 345 } 346 } 347 } 348 case lapack.Frobenius: 349 panic("not implemented") 350 default: 351 panic("invalid norm") 352 } 353 return value 354 } 355 356 // dlantr is a local implementation of Dlantr to keep code paths independent. 357 func dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 { 358 // Quick return if possible. 359 minmn := min(m, n) 360 if minmn == 0 { 361 return 0 362 } 363 switch norm { 364 case lapack.MaxAbs: 365 if diag == blas.Unit { 366 value := 1.0 367 if uplo == blas.Upper { 368 for i := 0; i < m; i++ { 369 for j := i + 1; j < n; j++ { 370 tmp := math.Abs(a[i*lda+j]) 371 if math.IsNaN(tmp) { 372 return tmp 373 } 374 if tmp > value { 375 value = tmp 376 } 377 } 378 } 379 return value 380 } 381 for i := 1; i < m; i++ { 382 for j := 0; j < min(i, n); j++ { 383 tmp := math.Abs(a[i*lda+j]) 384 if math.IsNaN(tmp) { 385 return tmp 386 } 387 if tmp > value { 388 value = tmp 389 } 390 } 391 } 392 return value 393 } 394 var value float64 395 if uplo == blas.Upper { 396 for i := 0; i < m; i++ { 397 for j := i; j < n; j++ { 398 tmp := math.Abs(a[i*lda+j]) 399 if math.IsNaN(tmp) { 400 return tmp 401 } 402 if tmp > value { 403 value = tmp 404 } 405 } 406 } 407 return value 408 } 409 for i := 0; i < m; i++ { 410 for j := 0; j <= min(i, n-1); j++ { 411 tmp := math.Abs(a[i*lda+j]) 412 if math.IsNaN(tmp) { 413 return tmp 414 } 415 if tmp > value { 416 value = tmp 417 } 418 } 419 } 420 return value 421 case lapack.MaxColumnSum: 422 if diag == blas.Unit { 423 for i := 0; i < minmn; i++ { 424 work[i] = 1 425 } 426 for i := minmn; i < n; i++ { 427 work[i] = 0 428 } 429 if uplo == blas.Upper { 430 for i := 0; i < m; i++ { 431 for j := i + 1; j < n; j++ { 432 work[j] += math.Abs(a[i*lda+j]) 433 } 434 } 435 } else { 436 for i := 1; i < m; i++ { 437 for j := 0; j < min(i, n); j++ { 438 work[j] += math.Abs(a[i*lda+j]) 439 } 440 } 441 } 442 } else { 443 for i := 0; i < n; i++ { 444 work[i] = 0 445 } 446 if uplo == blas.Upper { 447 for i := 0; i < m; i++ { 448 for j := i; j < n; j++ { 449 work[j] += math.Abs(a[i*lda+j]) 450 } 451 } 452 } else { 453 for i := 0; i < m; i++ { 454 for j := 0; j <= min(i, n-1); j++ { 455 work[j] += math.Abs(a[i*lda+j]) 456 } 457 } 458 } 459 } 460 var max float64 461 for _, v := range work[:n] { 462 if math.IsNaN(v) { 463 return math.NaN() 464 } 465 if v > max { 466 max = v 467 } 468 } 469 return max 470 case lapack.MaxRowSum: 471 var maxsum float64 472 if diag == blas.Unit { 473 if uplo == blas.Upper { 474 for i := 0; i < m; i++ { 475 var sum float64 476 if i < minmn { 477 sum = 1 478 } 479 for j := i + 1; j < n; j++ { 480 sum += math.Abs(a[i*lda+j]) 481 } 482 if math.IsNaN(sum) { 483 return math.NaN() 484 } 485 if sum > maxsum { 486 maxsum = sum 487 } 488 } 489 return maxsum 490 } else { 491 for i := 0; i < m; i++ { 492 var sum float64 493 if i < minmn { 494 sum = 1 495 } 496 for j := 0; j < min(i, n); j++ { 497 sum += math.Abs(a[i*lda+j]) 498 } 499 if math.IsNaN(sum) { 500 return math.NaN() 501 } 502 if sum > maxsum { 503 maxsum = sum 504 } 505 } 506 return maxsum 507 } 508 } else { 509 if uplo == blas.Upper { 510 for i := 0; i < m; i++ { 511 var sum float64 512 for j := i; j < n; j++ { 513 sum += math.Abs(a[i*lda+j]) 514 } 515 if math.IsNaN(sum) { 516 return sum 517 } 518 if sum > maxsum { 519 maxsum = sum 520 } 521 } 522 return maxsum 523 } else { 524 for i := 0; i < m; i++ { 525 var sum float64 526 for j := 0; j <= min(i, n-1); j++ { 527 sum += math.Abs(a[i*lda+j]) 528 } 529 if math.IsNaN(sum) { 530 return sum 531 } 532 if sum > maxsum { 533 maxsum = sum 534 } 535 } 536 return maxsum 537 } 538 } 539 case lapack.Frobenius: 540 panic("not implemented") 541 default: 542 panic("invalid norm") 543 } 544 } 545 546 // dlantb is a local implementation of Dlantb to keep code paths independent. 547 func dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64 { 548 if n == 0 { 549 return 0 550 } 551 var value float64 552 switch norm { 553 case lapack.MaxAbs: 554 if uplo == blas.Upper { 555 var jfirst int 556 if diag == blas.Unit { 557 value = 1 558 jfirst = 1 559 } 560 for i := 0; i < n; i++ { 561 for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { 562 if math.IsNaN(aij) { 563 return aij 564 } 565 aij = math.Abs(aij) 566 if aij > value { 567 value = aij 568 } 569 } 570 } 571 } else { 572 jlast := k + 1 573 if diag == blas.Unit { 574 value = 1 575 jlast = k 576 } 577 for i := 0; i < n; i++ { 578 for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { 579 if math.IsNaN(aij) { 580 return math.NaN() 581 } 582 aij = math.Abs(aij) 583 if aij > value { 584 value = aij 585 } 586 } 587 } 588 } 589 case lapack.MaxRowSum: 590 var sum float64 591 if uplo == blas.Upper { 592 var jfirst int 593 if diag == blas.Unit { 594 jfirst = 1 595 } 596 for i := 0; i < n; i++ { 597 sum = 0 598 if diag == blas.Unit { 599 sum = 1 600 } 601 for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { 602 sum += math.Abs(aij) 603 } 604 if math.IsNaN(sum) { 605 return math.NaN() 606 } 607 if sum > value { 608 value = sum 609 } 610 } 611 } else { 612 jlast := k + 1 613 if diag == blas.Unit { 614 jlast = k 615 } 616 for i := 0; i < n; i++ { 617 sum = 0 618 if diag == blas.Unit { 619 sum = 1 620 } 621 for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] { 622 sum += math.Abs(aij) 623 } 624 if math.IsNaN(sum) { 625 return math.NaN() 626 } 627 if sum > value { 628 value = sum 629 } 630 } 631 } 632 case lapack.MaxColumnSum: 633 work = work[:n] 634 if diag == blas.Unit { 635 for i := range work { 636 work[i] = 1 637 } 638 } else { 639 for i := range work { 640 work[i] = 0 641 } 642 } 643 if uplo == blas.Upper { 644 var jfirst int 645 if diag == blas.Unit { 646 jfirst = 1 647 } 648 for i := 0; i < n; i++ { 649 for j, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] { 650 work[i+jfirst+j] += math.Abs(aij) 651 } 652 } 653 } else { 654 jlast := k + 1 655 if diag == blas.Unit { 656 jlast = k 657 } 658 for i := 0; i < n; i++ { 659 off := max(0, k-i) 660 for j, aij := range a[i*lda+off : i*lda+jlast] { 661 work[i+j+off-k] += math.Abs(aij) 662 } 663 } 664 } 665 for _, wi := range work { 666 if math.IsNaN(wi) { 667 return math.NaN() 668 } 669 if wi > value { 670 value = wi 671 } 672 } 673 case lapack.Frobenius: 674 panic("not implemented") 675 default: 676 panic("invalid norm") 677 } 678 return value 679 }