gonum.org/v1/gonum@v0.15.1-0.20240517103525-f853624cb1bb/mat/dense_test.go (about) 1 // Copyright ©2013 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 mat 6 7 import ( 8 "fmt" 9 "math" 10 "reflect" 11 "strings" 12 "testing" 13 14 "golang.org/x/exp/rand" 15 16 "gonum.org/v1/gonum/blas/blas64" 17 "gonum.org/v1/gonum/floats" 18 "gonum.org/v1/gonum/stat/combin" 19 ) 20 21 func TestNewDense(t *testing.T) { 22 t.Parallel() 23 for i, test := range []struct { 24 a []float64 25 rows, cols int 26 min, max float64 27 fro float64 28 mat *Dense 29 }{ 30 { 31 []float64{ 32 0, 0, 0, 33 0, 0, 0, 34 0, 0, 0, 35 }, 36 3, 3, 37 0, 0, 38 0, 39 &Dense{ 40 mat: blas64.General{ 41 Rows: 3, Cols: 3, 42 Stride: 3, 43 Data: []float64{0, 0, 0, 0, 0, 0, 0, 0, 0}, 44 }, 45 capRows: 3, capCols: 3, 46 }, 47 }, 48 { 49 []float64{ 50 1, 1, 1, 51 1, 1, 1, 52 1, 1, 1, 53 }, 54 3, 3, 55 1, 1, 56 3, 57 &Dense{ 58 mat: blas64.General{ 59 Rows: 3, Cols: 3, 60 Stride: 3, 61 Data: []float64{1, 1, 1, 1, 1, 1, 1, 1, 1}, 62 }, 63 capRows: 3, capCols: 3, 64 }, 65 }, 66 { 67 []float64{ 68 1, 0, 0, 69 0, 1, 0, 70 0, 0, 1, 71 }, 72 3, 3, 73 0, 1, 74 1.7320508075688772, 75 &Dense{ 76 mat: blas64.General{ 77 Rows: 3, Cols: 3, 78 Stride: 3, 79 Data: []float64{1, 0, 0, 0, 1, 0, 0, 0, 1}, 80 }, 81 capRows: 3, capCols: 3, 82 }, 83 }, 84 { 85 []float64{ 86 -1, 0, 0, 87 0, -1, 0, 88 0, 0, -1, 89 }, 90 3, 3, 91 -1, 0, 92 1.7320508075688772, 93 &Dense{ 94 mat: blas64.General{ 95 Rows: 3, Cols: 3, 96 Stride: 3, 97 Data: []float64{-1, 0, 0, 0, -1, 0, 0, 0, -1}, 98 }, 99 capRows: 3, capCols: 3, 100 }, 101 }, 102 { 103 []float64{ 104 1, 2, 3, 105 4, 5, 6, 106 }, 107 2, 3, 108 1, 6, 109 9.539392014169458, 110 &Dense{ 111 mat: blas64.General{ 112 Rows: 2, Cols: 3, 113 Stride: 3, 114 Data: []float64{1, 2, 3, 4, 5, 6}, 115 }, 116 capRows: 2, capCols: 3, 117 }, 118 }, 119 { 120 []float64{ 121 1, 2, 122 3, 4, 123 5, 6, 124 }, 125 3, 2, 126 1, 6, 127 9.539392014169458, 128 &Dense{ 129 mat: blas64.General{ 130 Rows: 3, Cols: 2, 131 Stride: 2, 132 Data: []float64{1, 2, 3, 4, 5, 6}, 133 }, 134 capRows: 3, capCols: 2, 135 }, 136 }, 137 } { 138 m := NewDense(test.rows, test.cols, test.a) 139 rows, cols := m.Dims() 140 if rows != test.rows { 141 t.Errorf("unexpected number of rows for test %d: got: %d want: %d", i, rows, test.rows) 142 } 143 if cols != test.cols { 144 t.Errorf("unexpected number of cols for test %d: got: %d want: %d", i, cols, test.cols) 145 } 146 if min := Min(m); min != test.min { 147 t.Errorf("unexpected min for test %d: got: %v want: %v", i, min, test.min) 148 } 149 if max := Max(m); max != test.max { 150 t.Errorf("unexpected max for test %d: got: %v want: %v", i, max, test.max) 151 } 152 if fro := Norm(m, 2); math.Abs(Norm(m, 2)-test.fro) > 1e-14 { 153 t.Errorf("unexpected Frobenius norm for test %d: got: %v want: %v", i, fro, test.fro) 154 } 155 if !reflect.DeepEqual(m, test.mat) { 156 t.Errorf("unexpected matrix for test %d", i) 157 } 158 if !Equal(m, test.mat) { 159 t.Errorf("matrix does not equal expected matrix for test %d", i) 160 } 161 } 162 } 163 164 func TestDenseAtSet(t *testing.T) { 165 t.Parallel() 166 for test, af := range [][][]float64{ 167 {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, // even 168 {{1, 2}, {4, 5}, {7, 8}}, // wide 169 {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, //skinny 170 } { 171 m := NewDense(flatten(af)) 172 rows, cols := m.Dims() 173 for i := 0; i < rows; i++ { 174 for j := 0; j < cols; j++ { 175 if m.At(i, j) != af[i][j] { 176 t.Errorf("unexpected value for At(%d, %d) for test %d: got: %v want: %v", 177 i, j, test, m.At(i, j), af[i][j]) 178 } 179 180 v := float64(i * j) 181 m.Set(i, j, v) 182 if m.At(i, j) != v { 183 t.Errorf("unexpected value for At(%d, %d) after Set(%[1]d, %d, %v) for test %d: got: %v want: %[3]v", 184 i, j, v, test, m.At(i, j)) 185 } 186 } 187 } 188 // Check access out of bounds fails 189 for _, row := range []int{-1, rows, rows + 1} { 190 panicked, message := panics(func() { m.At(row, 0) }) 191 if !panicked || message != ErrRowAccess.Error() { 192 t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) 193 } 194 } 195 for _, col := range []int{-1, cols, cols + 1} { 196 panicked, message := panics(func() { m.At(0, col) }) 197 if !panicked || message != ErrColAccess.Error() { 198 t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) 199 } 200 } 201 202 // Check Set out of bounds 203 for _, row := range []int{-1, rows, rows + 1} { 204 panicked, message := panics(func() { m.Set(row, 0, 1.2) }) 205 if !panicked || message != ErrRowAccess.Error() { 206 t.Errorf("expected panic for invalid row access N=%d r=%d", rows, row) 207 } 208 } 209 for _, col := range []int{-1, cols, cols + 1} { 210 panicked, message := panics(func() { m.Set(0, col, 1.2) }) 211 if !panicked || message != ErrColAccess.Error() { 212 t.Errorf("expected panic for invalid column access N=%d c=%d", cols, col) 213 } 214 } 215 } 216 } 217 218 func TestDenseSetRowColumn(t *testing.T) { 219 t.Parallel() 220 for _, as := range [][][]float64{ 221 {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 222 {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}, 223 {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, 224 } { 225 for ri, row := range as { 226 a := NewDense(flatten(as)) 227 m := &Dense{} 228 m.CloneFrom(a) 229 a.SetRow(ri, make([]float64, a.mat.Cols)) 230 m.Sub(m, a) 231 nt := Norm(m, 2) 232 nr := floats.Norm(row, 2) 233 if math.Abs(nt-nr) > 1e-14 { 234 t.Errorf("Row %d norm mismatch, want: %g, got: %g", ri, nr, nt) 235 } 236 } 237 238 for ci := range as[0] { 239 a := NewDense(flatten(as)) 240 m := &Dense{} 241 m.CloneFrom(a) 242 a.SetCol(ci, make([]float64, a.mat.Rows)) 243 col := make([]float64, a.mat.Rows) 244 for j := range col { 245 col[j] = float64(ci + 1 + j*a.mat.Cols) 246 } 247 m.Sub(m, a) 248 nt := Norm(m, 2) 249 nc := floats.Norm(col, 2) 250 if math.Abs(nt-nc) > 1e-14 { 251 t.Errorf("Column %d norm mismatch, want: %g, got: %g", ci, nc, nt) 252 } 253 } 254 } 255 } 256 257 func TestDenseZero(t *testing.T) { 258 t.Parallel() 259 // Elements that equal 1 should be set to zero, elements that equal -1 260 // should remain unchanged. 261 for _, test := range []*Dense{ 262 { 263 mat: blas64.General{ 264 Rows: 4, 265 Cols: 3, 266 Stride: 5, 267 Data: []float64{ 268 1, 1, 1, -1, -1, 269 1, 1, 1, -1, -1, 270 1, 1, 1, -1, -1, 271 1, 1, 1, -1, -1, 272 }, 273 }, 274 }, 275 } { 276 dataCopy := make([]float64, len(test.mat.Data)) 277 copy(dataCopy, test.mat.Data) 278 test.Zero() 279 for i, v := range test.mat.Data { 280 if dataCopy[i] != -1 && v != 0 { 281 t.Errorf("Matrix not zeroed in bounds") 282 } 283 if dataCopy[i] == -1 && v != -1 { 284 t.Errorf("Matrix zeroed out of bounds") 285 } 286 } 287 } 288 } 289 290 func TestDenseRowColView(t *testing.T) { 291 t.Parallel() 292 for _, test := range []struct { 293 mat [][]float64 294 }{ 295 { 296 mat: [][]float64{ 297 {1, 2, 3, 4, 5}, 298 {6, 7, 8, 9, 10}, 299 {11, 12, 13, 14, 15}, 300 {16, 17, 18, 19, 20}, 301 {21, 22, 23, 24, 25}, 302 }, 303 }, 304 { 305 mat: [][]float64{ 306 {1, 2, 3, 4}, 307 {6, 7, 8, 9}, 308 {11, 12, 13, 14}, 309 {16, 17, 18, 19}, 310 {21, 22, 23, 24}, 311 }, 312 }, 313 { 314 mat: [][]float64{ 315 {1, 2, 3, 4, 5}, 316 {6, 7, 8, 9, 10}, 317 {11, 12, 13, 14, 15}, 318 {16, 17, 18, 19, 20}, 319 }, 320 }, 321 } { 322 // This over cautious approach to building a matrix data 323 // slice is to ensure that changes to flatten in the future 324 // do not mask a regression to the issue identified in 325 // gonum/matrix#110. 326 rows, cols, flat := flatten(test.mat) 327 m := NewDense(rows, cols, flat[:len(flat):len(flat)]) 328 329 for _, row := range []int{-1, rows, rows + 1} { 330 panicked, message := panics(func() { m.At(row, 0) }) 331 if !panicked || message != ErrRowAccess.Error() { 332 t.Errorf("expected panic for invalid row access rows=%d r=%d", rows, row) 333 } 334 } 335 for _, col := range []int{-1, cols, cols + 1} { 336 panicked, message := panics(func() { m.At(0, col) }) 337 if !panicked || message != ErrColAccess.Error() { 338 t.Errorf("expected panic for invalid column access cols=%d c=%d", cols, col) 339 } 340 } 341 342 for i := 0; i < rows; i++ { 343 vr := m.RowView(i) 344 if vr.Len() != cols { 345 t.Errorf("unexpected number of columns: got: %d want: %d", vr.Len(), cols) 346 } 347 for j := 0; j < cols; j++ { 348 if got := vr.At(j, 0); got != test.mat[i][j] { 349 t.Errorf("unexpected value for row.At(%d, 0): got: %v want: %v", 350 j, got, test.mat[i][j]) 351 } 352 } 353 } 354 for j := 0; j < cols; j++ { 355 vc := m.ColView(j) 356 if vc.Len() != rows { 357 t.Errorf("unexpected number of rows: got: %d want: %d", vc.Len(), rows) 358 } 359 for i := 0; i < rows; i++ { 360 if got := vc.At(i, 0); got != test.mat[i][j] { 361 t.Errorf("unexpected value for col.At(%d, 0): got: %v want: %v", 362 i, got, test.mat[i][j]) 363 } 364 } 365 } 366 m = m.Slice(1, rows-1, 1, cols-1).(*Dense) 367 for i := 1; i < rows-1; i++ { 368 vr := m.RowView(i - 1) 369 if vr.Len() != cols-2 { 370 t.Errorf("unexpected number of columns: got: %d want: %d", vr.Len(), cols-2) 371 } 372 for j := 1; j < cols-1; j++ { 373 if got := vr.At(j-1, 0); got != test.mat[i][j] { 374 t.Errorf("unexpected value for row.At(%d, 0): got: %v want: %v", 375 j-1, got, test.mat[i][j]) 376 } 377 } 378 } 379 for j := 1; j < cols-1; j++ { 380 vc := m.ColView(j - 1) 381 if vc.Len() != rows-2 { 382 t.Errorf("unexpected number of rows: got: %d want: %d", vc.Len(), rows-2) 383 } 384 for i := 1; i < rows-1; i++ { 385 if got := vc.At(i-1, 0); got != test.mat[i][j] { 386 t.Errorf("unexpected value for col.At(%d, 0): got: %v want: %v", 387 i-1, got, test.mat[i][j]) 388 } 389 } 390 } 391 } 392 } 393 394 func TestDenseDiagView(t *testing.T) { 395 t.Parallel() 396 for cas, test := range []*Dense{ 397 NewDense(1, 1, []float64{1}), 398 NewDense(2, 2, []float64{1, 2, 3, 4}), 399 NewDense(3, 4, []float64{ 400 1, 2, 3, 4, 401 5, 6, 7, 8, 402 9, 10, 11, 12, 403 }), 404 NewDense(4, 3, []float64{ 405 1, 2, 3, 406 4, 5, 6, 407 7, 8, 9, 408 10, 11, 12, 409 }), 410 } { 411 testDiagView(t, cas, test) 412 } 413 } 414 415 func TestDenseGrow(t *testing.T) { 416 t.Parallel() 417 m := &Dense{} 418 m = m.Grow(10, 10).(*Dense) 419 rows, cols := m.Dims() 420 capRows, capCols := m.Caps() 421 if rows != 10 { 422 t.Errorf("unexpected value for rows: got: %d want: 10", rows) 423 } 424 if cols != 10 { 425 t.Errorf("unexpected value for cols: got: %d want: 10", cols) 426 } 427 if capRows != 10 { 428 t.Errorf("unexpected value for capRows: got: %d want: 10", capRows) 429 } 430 if capCols != 10 { 431 t.Errorf("unexpected value for capCols: got: %d want: 10", capCols) 432 } 433 434 // Test grow within caps is in-place. 435 m.Set(1, 1, 1) 436 v := m.Slice(1, 5, 1, 5).(*Dense) 437 if v.At(0, 0) != m.At(1, 1) { 438 t.Errorf("unexpected viewed element value: got: %v want: %v", v.At(0, 0), m.At(1, 1)) 439 } 440 v = v.Grow(5, 5).(*Dense) 441 if !Equal(v, m.Slice(1, 10, 1, 10)) { 442 t.Error("unexpected view value after grow") 443 } 444 445 // Test grow bigger than caps copies. 446 v = v.Grow(5, 5).(*Dense) 447 if !Equal(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { 448 t.Error("unexpected mismatched common view value after grow") 449 } 450 v.Set(0, 0, 0) 451 if Equal(v.Slice(0, 9, 0, 9), m.Slice(1, 10, 1, 10)) { 452 t.Error("unexpected matching view value after grow past capacity") 453 } 454 455 // Test grow uses existing data slice when matrix is zero size. 456 v.Reset() 457 p, l := &v.mat.Data[:1][0], cap(v.mat.Data) 458 *p = 1 // This element is at position (-1, -1) relative to v and so should not be visible. 459 v = v.Grow(5, 5).(*Dense) 460 if &v.mat.Data[:1][0] != p { 461 t.Error("grow unexpectedly copied slice within cap limit") 462 } 463 if cap(v.mat.Data) != l { 464 t.Errorf("unexpected change in data slice capacity: got: %d want: %d", cap(v.mat.Data), l) 465 } 466 if v.At(0, 0) != 0 { 467 t.Errorf("unexpected value for At(0, 0): got: %v want: 0", v.At(0, 0)) 468 } 469 } 470 471 func TestDenseAdd(t *testing.T) { 472 t.Parallel() 473 for i, test := range []struct { 474 a, b, r [][]float64 475 }{ 476 { 477 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 478 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 479 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 480 }, 481 { 482 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 483 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 484 [][]float64{{2, 2, 2}, {2, 2, 2}, {2, 2, 2}}, 485 }, 486 { 487 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 488 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 489 [][]float64{{2, 0, 0}, {0, 2, 0}, {0, 0, 2}}, 490 }, 491 { 492 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 493 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 494 [][]float64{{-2, 0, 0}, {0, -2, 0}, {0, 0, -2}}, 495 }, 496 { 497 [][]float64{{1, 2, 3}, {4, 5, 6}}, 498 [][]float64{{1, 2, 3}, {4, 5, 6}}, 499 [][]float64{{2, 4, 6}, {8, 10, 12}}, 500 }, 501 } { 502 a := NewDense(flatten(test.a)) 503 b := NewDense(flatten(test.b)) 504 r := NewDense(flatten(test.r)) 505 506 var temp Dense 507 temp.Add(a, b) 508 if !Equal(&temp, r) { 509 t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", 510 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 511 } 512 513 zero(temp.mat.Data) 514 temp.Add(a, b) 515 if !Equal(&temp, r) { 516 t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", 517 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 518 } 519 520 // These probably warrant a better check and failure. They should never happen in the wild though. 521 temp.mat.Data = nil 522 panicked, message := panics(func() { temp.Add(a, b) }) 523 if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { 524 t.Error("expected runtime panic for nil data slice") 525 } 526 527 a.Add(a, b) 528 if !Equal(a, r) { 529 t.Errorf("unexpected result from Add for test %d %v Add %v: got: %v want: %v", 530 i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) 531 } 532 } 533 534 panicked, message := panics(func() { 535 m := NewDense(10, 10, nil) 536 a := NewDense(5, 5, nil) 537 m.Slice(1, 6, 1, 6).(*Dense).Add(a, m.Slice(2, 7, 2, 7)) 538 }) 539 if !panicked { 540 t.Error("expected panic for overlapping matrices") 541 } 542 if message != regionOverlap { 543 t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) 544 } 545 546 method := func(receiver, a, b Matrix) { 547 type Adder interface { 548 Add(a, b Matrix) 549 } 550 rd := receiver.(Adder) 551 rd.Add(a, b) 552 } 553 denseComparison := func(receiver, a, b *Dense) { 554 receiver.Add(a, b) 555 } 556 testTwoInput(t, "Add", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) 557 } 558 559 func TestDenseSub(t *testing.T) { 560 t.Parallel() 561 for i, test := range []struct { 562 a, b, r [][]float64 563 }{ 564 { 565 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 566 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 567 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 568 }, 569 { 570 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 571 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 572 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 573 }, 574 { 575 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 576 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 577 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 578 }, 579 { 580 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 581 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 582 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 583 }, 584 { 585 [][]float64{{1, 2, 3}, {4, 5, 6}}, 586 [][]float64{{1, 2, 3}, {4, 5, 6}}, 587 [][]float64{{0, 0, 0}, {0, 0, 0}}, 588 }, 589 } { 590 a := NewDense(flatten(test.a)) 591 b := NewDense(flatten(test.b)) 592 r := NewDense(flatten(test.r)) 593 594 var temp Dense 595 temp.Sub(a, b) 596 if !Equal(&temp, r) { 597 t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", 598 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 599 } 600 601 zero(temp.mat.Data) 602 temp.Sub(a, b) 603 if !Equal(&temp, r) { 604 t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", 605 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 606 } 607 608 // These probably warrant a better check and failure. They should never happen in the wild though. 609 temp.mat.Data = nil 610 panicked, message := panics(func() { temp.Sub(a, b) }) 611 if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { 612 t.Error("expected runtime panic for nil data slice") 613 } 614 615 a.Sub(a, b) 616 if !Equal(a, r) { 617 t.Errorf("unexpected result from Sub for test %d %v Sub %v: got: %v want: %v", 618 i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) 619 } 620 } 621 622 panicked, message := panics(func() { 623 m := NewDense(10, 10, nil) 624 a := NewDense(5, 5, nil) 625 m.Slice(1, 6, 1, 6).(*Dense).Sub(a, m.Slice(2, 7, 2, 7)) 626 }) 627 if !panicked { 628 t.Error("expected panic for overlapping matrices") 629 } 630 if message != regionOverlap { 631 t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) 632 } 633 634 method := func(receiver, a, b Matrix) { 635 type Suber interface { 636 Sub(a, b Matrix) 637 } 638 rd := receiver.(Suber) 639 rd.Sub(a, b) 640 } 641 denseComparison := func(receiver, a, b *Dense) { 642 receiver.Sub(a, b) 643 } 644 testTwoInput(t, "Sub", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) 645 } 646 647 func TestDenseMulElem(t *testing.T) { 648 t.Parallel() 649 for i, test := range []struct { 650 a, b, r [][]float64 651 }{ 652 { 653 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 654 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 655 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 656 }, 657 { 658 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 659 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 660 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 661 }, 662 { 663 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 664 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 665 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 666 }, 667 { 668 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 669 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 670 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 671 }, 672 { 673 [][]float64{{1, 2, 3}, {4, 5, 6}}, 674 [][]float64{{1, 2, 3}, {4, 5, 6}}, 675 [][]float64{{1, 4, 9}, {16, 25, 36}}, 676 }, 677 } { 678 a := NewDense(flatten(test.a)) 679 b := NewDense(flatten(test.b)) 680 r := NewDense(flatten(test.r)) 681 682 var temp Dense 683 temp.MulElem(a, b) 684 if !Equal(&temp, r) { 685 t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", 686 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 687 } 688 689 zero(temp.mat.Data) 690 temp.MulElem(a, b) 691 if !Equal(&temp, r) { 692 t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", 693 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 694 } 695 696 // These probably warrant a better check and failure. They should never happen in the wild though. 697 temp.mat.Data = nil 698 panicked, message := panics(func() { temp.MulElem(a, b) }) 699 if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { 700 t.Error("expected runtime panic for nil data slice") 701 } 702 703 a.MulElem(a, b) 704 if !Equal(a, r) { 705 t.Errorf("unexpected result from MulElem for test %d %v MulElem %v: got: %v want: %v", 706 i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) 707 } 708 } 709 710 panicked, message := panics(func() { 711 m := NewDense(10, 10, nil) 712 a := NewDense(5, 5, nil) 713 m.Slice(1, 6, 1, 6).(*Dense).MulElem(a, m.Slice(2, 7, 2, 7)) 714 }) 715 if !panicked { 716 t.Error("expected panic for overlapping matrices") 717 } 718 if message != regionOverlap { 719 t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) 720 } 721 722 method := func(receiver, a, b Matrix) { 723 type ElemMuler interface { 724 MulElem(a, b Matrix) 725 } 726 rd := receiver.(ElemMuler) 727 rd.MulElem(a, b) 728 } 729 denseComparison := func(receiver, a, b *Dense) { 730 receiver.MulElem(a, b) 731 } 732 testTwoInput(t, "MulElem", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) 733 } 734 735 // A comparison that treats NaNs as equal, for testing. 736 func (m *Dense) same(b Matrix) bool { 737 br, bc := b.Dims() 738 if br != m.mat.Rows || bc != m.mat.Cols { 739 return false 740 } 741 for r := 0; r < br; r++ { 742 for c := 0; c < bc; c++ { 743 if av, bv := m.At(r, c), b.At(r, c); av != bv && !(math.IsNaN(av) && math.IsNaN(bv)) { 744 return false 745 } 746 } 747 } 748 return true 749 } 750 751 func TestDenseDivElem(t *testing.T) { 752 t.Parallel() 753 for i, test := range []struct { 754 a, b, r [][]float64 755 }{ 756 { 757 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 758 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 759 [][]float64{{math.Inf(1), math.NaN(), math.NaN()}, {math.NaN(), math.Inf(1), math.NaN()}, {math.NaN(), math.NaN(), math.Inf(1)}}, 760 }, 761 { 762 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 763 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 764 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 765 }, 766 { 767 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 768 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 769 [][]float64{{1, math.NaN(), math.NaN()}, {math.NaN(), 1, math.NaN()}, {math.NaN(), math.NaN(), 1}}, 770 }, 771 { 772 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 773 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 774 [][]float64{{1, math.NaN(), math.NaN()}, {math.NaN(), 1, math.NaN()}, {math.NaN(), math.NaN(), 1}}, 775 }, 776 { 777 [][]float64{{1, 2, 3}, {4, 5, 6}}, 778 [][]float64{{1, 2, 3}, {4, 5, 6}}, 779 [][]float64{{1, 1, 1}, {1, 1, 1}}, 780 }, 781 } { 782 a := NewDense(flatten(test.a)) 783 b := NewDense(flatten(test.b)) 784 r := NewDense(flatten(test.r)) 785 786 var temp Dense 787 temp.DivElem(a, b) 788 if !temp.same(r) { 789 t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", 790 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 791 } 792 793 zero(temp.mat.Data) 794 temp.DivElem(a, b) 795 if !temp.same(r) { 796 t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", 797 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 798 } 799 800 // These probably warrant a better check and failure. They should never happen in the wild though. 801 temp.mat.Data = nil 802 panicked, message := panics(func() { temp.DivElem(a, b) }) 803 if !panicked || !strings.HasPrefix(message, "runtime error: index out of range") { 804 t.Error("expected runtime panic for nil data slice") 805 } 806 807 a.DivElem(a, b) 808 if !a.same(r) { 809 t.Errorf("unexpected result from DivElem for test %d %v DivElem %v: got: %v want: %v", 810 i, test.a, test.b, unflatten(a.mat.Rows, a.mat.Cols, a.mat.Data), test.r) 811 } 812 } 813 814 panicked, message := panics(func() { 815 m := NewDense(10, 10, nil) 816 a := NewDense(5, 5, nil) 817 m.Slice(1, 6, 1, 6).(*Dense).DivElem(a, m.Slice(2, 7, 2, 7)) 818 }) 819 if !panicked { 820 t.Error("expected panic for overlapping matrices") 821 } 822 if message != regionOverlap { 823 t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) 824 } 825 826 method := func(receiver, a, b Matrix) { 827 type ElemDiver interface { 828 DivElem(a, b Matrix) 829 } 830 rd := receiver.(ElemDiver) 831 rd.DivElem(a, b) 832 } 833 denseComparison := func(receiver, a, b *Dense) { 834 receiver.DivElem(a, b) 835 } 836 testTwoInput(t, "DivElem", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameRectangular, 1e-14) 837 } 838 839 func TestDenseMul(t *testing.T) { 840 t.Parallel() 841 for i, test := range []struct { 842 a, b, r [][]float64 843 }{ 844 { 845 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 846 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 847 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 848 }, 849 { 850 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 851 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 852 [][]float64{{3, 3, 3}, {3, 3, 3}, {3, 3, 3}}, 853 }, 854 { 855 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 856 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 857 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 858 }, 859 { 860 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 861 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 862 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 863 }, 864 { 865 [][]float64{{1, 2, 3}, {4, 5, 6}}, 866 [][]float64{{1, 2}, {3, 4}, {5, 6}}, 867 [][]float64{{22, 28}, {49, 64}}, 868 }, 869 { 870 [][]float64{{0, 1, 1}, {0, 1, 1}, {0, 1, 1}}, 871 [][]float64{{0, 1, 1}, {0, 1, 1}, {0, 1, 1}}, 872 [][]float64{{0, 2, 2}, {0, 2, 2}, {0, 2, 2}}, 873 }, 874 } { 875 a := NewDense(flatten(test.a)) 876 b := NewDense(flatten(test.b)) 877 r := NewDense(flatten(test.r)) 878 879 var temp Dense 880 temp.Mul(a, b) 881 if !Equal(&temp, r) { 882 t.Errorf("unexpected result from Mul for test %d %v Mul %v: got: %v want: %v", 883 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 884 } 885 886 zero(temp.mat.Data) 887 temp.Mul(a, b) 888 if !Equal(&temp, r) { 889 t.Errorf("unexpected result from Mul for test %d %v Mul %v: got: %v want: %v", 890 i, test.a, test.b, unflatten(temp.mat.Rows, temp.mat.Cols, temp.mat.Data), test.r) 891 } 892 893 // These probably warrant a better check and failure. They should never happen in the wild though. 894 temp.mat.Data = nil 895 panicked, message := panics(func() { temp.Mul(a, b) }) 896 if !panicked || message != "blas: insufficient length of c" { 897 if message != "" { 898 t.Errorf("expected runtime panic for nil data slice: got %q", message) 899 } else { 900 t.Error("expected runtime panic for nil data slice") 901 } 902 } 903 } 904 905 panicked, message := panics(func() { 906 m := NewDense(10, 10, nil) 907 a := NewDense(5, 5, nil) 908 m.Slice(1, 6, 1, 6).(*Dense).Mul(a, m.Slice(2, 7, 2, 7)) 909 }) 910 if !panicked { 911 t.Error("expected panic for overlapping matrices") 912 } 913 if message != regionOverlap { 914 t.Errorf("unexpected panic message: got: %q want: %q", message, regionOverlap) 915 } 916 917 method := func(receiver, a, b Matrix) { 918 type Muler interface { 919 Mul(a, b Matrix) 920 } 921 rd := receiver.(Muler) 922 rd.Mul(a, b) 923 } 924 denseComparison := func(receiver, a, b *Dense) { 925 receiver.Mul(a, b) 926 } 927 legalSizeMul := func(ar, ac, br, bc int) bool { 928 return ac == br 929 } 930 testTwoInput(t, "Mul", &Dense{}, method, denseComparison, legalTypesAll, legalSizeMul, 1e-14) 931 } 932 933 func randDense(size int, rho float64, src rand.Source) (*Dense, error) { 934 if size == 0 { 935 return nil, ErrZeroLength 936 } 937 d := &Dense{ 938 mat: blas64.General{ 939 Rows: size, Cols: size, Stride: size, 940 Data: make([]float64, size*size), 941 }, 942 capRows: size, capCols: size, 943 } 944 rnd := rand.New(src) 945 for i := 0; i < size; i++ { 946 for j := 0; j < size; j++ { 947 if rnd.Float64() < rho { 948 d.Set(i, j, rnd.NormFloat64()) 949 } 950 } 951 } 952 return d, nil 953 } 954 955 func TestDenseExp(t *testing.T) { 956 t.Parallel() 957 for i, test := range []struct { 958 a [][]float64 959 want [][]float64 960 mod func(*Dense) 961 }{ 962 // Expected values obtained from scipy.linalg.expm with the equivalent numpy.array. 963 { 964 a: [][]float64{{-49, 24}, {-64, 31}}, 965 want: [][]float64{{-0.735758758144758, 0.551819099658100}, {-1.471517599088267, 1.103638240715576}}, 966 }, 967 { 968 a: [][]float64{{-49, 24}, {-64, 31}}, 969 want: [][]float64{{-0.735758758144758, 0.551819099658100}, {-1.471517599088267, 1.103638240715576}}, 970 mod: func(a *Dense) { 971 d := make([]float64, 100) 972 for i := range d { 973 d[i] = math.NaN() 974 } 975 *a = *NewDense(10, 10, d).Slice(1, 3, 1, 3).(*Dense) 976 }, 977 }, 978 { 979 a: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 980 want: [][]float64{{2.71828182845905, 0, 0}, {0, 2.71828182845905, 0}, {0, 0, 2.71828182845905}}, 981 }, 982 { 983 a: [][]float64{ 984 {-200, 100, 100, 0}, 985 {100, -200, 0, 100}, 986 {100, 0, -200, 100}, 987 {0, 100, 100, -200}, 988 }, 989 want: [][]float64{ 990 {0.25, 0.25, 0.25, 0.25}, 991 {0.25, 0.25, 0.25, 0.25}, 992 {0.25, 0.25, 0.25, 0.25}, 993 {0.25, 0.25, 0.25, 0.25}, 994 }, 995 }, 996 } { 997 var got Dense 998 if test.mod != nil { 999 test.mod(&got) 1000 } 1001 got.Exp(NewDense(flatten(test.a))) 1002 want := NewDense(flatten(test.want)) 1003 if !EqualApprox(&got, want, 1e-14) { 1004 t.Errorf("unexpected result for Exp test %d\ngot:\n%v\nwant:\n%v", 1005 i, Formatted(&got), Formatted(want)) 1006 } 1007 } 1008 } 1009 1010 func TestDensePow(t *testing.T) { 1011 t.Parallel() 1012 for i, test := range []struct { 1013 a [][]float64 1014 n int 1015 mod func(*Dense) 1016 want [][]float64 1017 }{ 1018 { 1019 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1020 n: 0, 1021 want: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1022 }, 1023 { 1024 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1025 n: 0, 1026 want: [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1027 mod: func(a *Dense) { 1028 d := make([]float64, 100) 1029 for i := range d { 1030 d[i] = math.NaN() 1031 } 1032 *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) 1033 }, 1034 }, 1035 { 1036 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1037 n: 1, 1038 want: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1039 }, 1040 { 1041 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1042 n: 1, 1043 want: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1044 mod: func(a *Dense) { 1045 d := make([]float64, 100) 1046 for i := range d { 1047 d[i] = math.NaN() 1048 } 1049 *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) 1050 }, 1051 }, 1052 { 1053 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1054 n: 2, 1055 want: [][]float64{{30, 36, 42}, {66, 81, 96}, {102, 126, 150}}, 1056 }, 1057 { 1058 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1059 n: 2, 1060 want: [][]float64{{30, 36, 42}, {66, 81, 96}, {102, 126, 150}}, 1061 mod: func(a *Dense) { 1062 d := make([]float64, 100) 1063 for i := range d { 1064 d[i] = math.NaN() 1065 } 1066 *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) 1067 }, 1068 }, 1069 { 1070 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1071 n: 3, 1072 want: [][]float64{{468, 576, 684}, {1062, 1305, 1548}, {1656, 2034, 2412}}, 1073 }, 1074 { 1075 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1076 n: 3, 1077 want: [][]float64{{468, 576, 684}, {1062, 1305, 1548}, {1656, 2034, 2412}}, 1078 mod: func(a *Dense) { 1079 d := make([]float64, 100) 1080 for i := range d { 1081 d[i] = math.NaN() 1082 } 1083 *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) 1084 }, 1085 }, 1086 } { 1087 var got Dense 1088 if test.mod != nil { 1089 test.mod(&got) 1090 } 1091 got.Pow(NewDense(flatten(test.a)), test.n) 1092 if !EqualApprox(&got, NewDense(flatten(test.want)), 1e-12) { 1093 t.Errorf("unexpected result for Pow test %d", i) 1094 } 1095 } 1096 } 1097 1098 func TestDenseKronecker(t *testing.T) { 1099 t.Parallel() 1100 for i, test := range []struct { 1101 a, b Matrix 1102 want *Dense 1103 }{ 1104 { 1105 a: NewDense(1, 3, []float64{1, 2, 3}), 1106 b: NewDense(3, 1, []float64{1, 2, 3}), 1107 want: NewDense(3, 3, []float64{ 1108 1, 2, 3, 1109 2, 4, 6, 1110 3, 6, 9, 1111 }), 1112 }, 1113 { 1114 a: NewDense(3, 1, []float64{1, 2, 3}), 1115 b: NewDense(1, 3, []float64{1, 2, 3}), 1116 want: NewDense(3, 3, []float64{ 1117 1, 2, 3, 1118 2, 4, 6, 1119 3, 6, 9, 1120 }), 1121 }, 1122 { 1123 a: NewDense(1, 3, []float64{1, 2, 3}), 1124 b: NewDense(2, 1, []float64{1, 2}), 1125 want: NewDense(2, 3, []float64{ 1126 1, 2, 3, 1127 2, 4, 6, 1128 }), 1129 }, 1130 { 1131 a: NewDense(2, 1, []float64{1, 2}), 1132 b: NewDense(1, 3, []float64{1, 2, 3}), 1133 want: NewDense(2, 3, []float64{ 1134 1, 2, 3, 1135 2, 4, 6, 1136 }), 1137 }, 1138 { 1139 a: NewDense(1, 2, []float64{1, 2}), 1140 b: NewDense(3, 1, []float64{1, 2, 3}), 1141 want: NewDense(3, 2, []float64{ 1142 1, 2, 1143 2, 4, 1144 3, 6, 1145 }), 1146 }, 1147 { 1148 a: NewDense(3, 1, []float64{1, 2, 3}), 1149 b: NewDense(1, 2, []float64{1, 2}), 1150 want: NewDense(3, 2, []float64{ 1151 1, 2, 1152 2, 4, 1153 3, 6, 1154 }), 1155 }, 1156 1157 // Examples from https://en.wikipedia.org/wiki/Kronecker_product. 1158 { 1159 a: NewDense(2, 2, []float64{1, 2, 3, 4}), 1160 b: NewDense(2, 2, []float64{0, 5, 6, 7}), 1161 want: NewDense(4, 4, []float64{ 1162 0, 5, 0, 10, 1163 6, 7, 12, 14, 1164 0, 15, 0, 20, 1165 18, 21, 24, 28, 1166 }), 1167 }, 1168 { 1169 a: NewDense(2, 3, []float64{ 1170 1, -4, 7, 1171 -2, 3, 3, 1172 }), 1173 b: NewDense(4, 4, []float64{ 1174 8, -9, -6, 5, 1175 1, -3, -4, 7, 1176 2, 8, -8, -3, 1177 1, 2, -5, -1, 1178 }), 1179 want: NewDense(8, 12, []float64{ 1180 8, -9, -6, 5, -32, 36, 24, -20, 56, -63, -42, 35, 1181 1, -3, -4, 7, -4, 12, 16, -28, 7, -21, -28, 49, 1182 2, 8, -8, -3, -8, -32, 32, 12, 14, 56, -56, -21, 1183 1, 2, -5, -1, -4, -8, 20, 4, 7, 14, -35, -7, 1184 -16, 18, 12, -10, 24, -27, -18, 15, 24, -27, -18, 15, 1185 -2, 6, 8, -14, 3, -9, -12, 21, 3, -9, -12, 21, 1186 -4, -16, 16, 6, 6, 24, -24, -9, 6, 24, -24, -9, 1187 -2, -4, 10, 2, 3, 6, -15, -3, 3, 6, -15, -3, 1188 }), 1189 }, 1190 } { 1191 var got Dense 1192 got.Kronecker(test.a, test.b) 1193 if !Equal(&got, test.want) { 1194 t.Errorf("unexpected result for test %d\ngot:%#v want:%#v", i, &got, test.want) 1195 } 1196 } 1197 } 1198 1199 func TestDenseScale(t *testing.T) { 1200 t.Parallel() 1201 for _, f := range []float64{0.5, 1, 3} { 1202 method := func(receiver, a Matrix) { 1203 type Scaler interface { 1204 Scale(f float64, a Matrix) 1205 } 1206 rd := receiver.(Scaler) 1207 rd.Scale(f, a) 1208 } 1209 denseComparison := func(receiver, a *Dense) { 1210 receiver.Scale(f, a) 1211 } 1212 testOneInput(t, "Scale", &Dense{}, method, denseComparison, isAnyType, isAnySize, 1e-14) 1213 } 1214 } 1215 1216 func TestDensePowN(t *testing.T) { 1217 t.Parallel() 1218 for i, test := range []struct { 1219 a [][]float64 1220 mod func(*Dense) 1221 }{ 1222 { 1223 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1224 }, 1225 { 1226 a: [][]float64{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, 1227 mod: func(a *Dense) { 1228 d := make([]float64, 100) 1229 for i := range d { 1230 d[i] = math.NaN() 1231 } 1232 *a = *NewDense(10, 10, d).Slice(1, 4, 1, 4).(*Dense) 1233 }, 1234 }, 1235 } { 1236 for n := 1; n <= 14; n++ { 1237 var got, want Dense 1238 if test.mod != nil { 1239 test.mod(&got) 1240 } 1241 got.Pow(NewDense(flatten(test.a)), n) 1242 want.iterativePow(NewDense(flatten(test.a)), n) 1243 if !Equal(&got, &want) { 1244 t.Errorf("unexpected result for iterative Pow test %d", i) 1245 } 1246 } 1247 } 1248 } 1249 1250 func (m *Dense) iterativePow(a Matrix, n int) { 1251 m.CloneFrom(a) 1252 for i := 1; i < n; i++ { 1253 m.Mul(m, a) 1254 } 1255 } 1256 1257 func TestDenseCloneT(t *testing.T) { 1258 t.Parallel() 1259 for i, test := range []struct { 1260 a, want [][]float64 1261 }{ 1262 { 1263 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1264 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1265 }, 1266 { 1267 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1268 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1269 }, 1270 { 1271 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1272 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1273 }, 1274 { 1275 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1276 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1277 }, 1278 { 1279 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1280 [][]float64{{1, 4}, {2, 5}, {3, 6}}, 1281 }, 1282 } { 1283 a := NewDense(flatten(test.a)) 1284 want := NewDense(flatten(test.want)) 1285 1286 var got, gotT Dense 1287 1288 for j := 0; j < 2; j++ { 1289 got.CloneFrom(a.T()) 1290 if !Equal(&got, want) { 1291 t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", 1292 i, j, test.a, test.want) 1293 } 1294 gotT.CloneFrom(got.T()) 1295 if !Equal(&gotT, a) { 1296 t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", 1297 i, j, test.a, test.want) 1298 } 1299 1300 zero(got.mat.Data) 1301 } 1302 } 1303 } 1304 1305 func TestDenseCopyT(t *testing.T) { 1306 t.Parallel() 1307 for i, test := range []struct { 1308 a, want [][]float64 1309 }{ 1310 { 1311 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1312 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1313 }, 1314 { 1315 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1316 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1317 }, 1318 { 1319 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1320 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1321 }, 1322 { 1323 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1324 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1325 }, 1326 { 1327 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1328 [][]float64{{1, 4}, {2, 5}, {3, 6}}, 1329 }, 1330 } { 1331 a := NewDense(flatten(test.a)) 1332 want := NewDense(flatten(test.want)) 1333 1334 ar, ac := a.Dims() 1335 got := NewDense(ac, ar, nil) 1336 rr := NewDense(ar, ac, nil) 1337 1338 for j := 0; j < 2; j++ { 1339 got.Copy(a.T()) 1340 if !Equal(got, want) { 1341 t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", 1342 i, j, test.a, test.want) 1343 } 1344 rr.Copy(got.T()) 1345 if !Equal(rr, a) { 1346 t.Errorf("expected transpose for test %d iteration %d: %v transpose = %v", 1347 i, j, test.a, test.want) 1348 } 1349 1350 zero(got.mat.Data) 1351 } 1352 } 1353 } 1354 1355 func TestDenseCopyDenseAlias(t *testing.T) { 1356 t.Parallel() 1357 for _, trans := range []bool{false, true} { 1358 for di := 0; di < 2; di++ { 1359 for dj := 0; dj < 2; dj++ { 1360 for si := 0; si < 2; si++ { 1361 for sj := 0; sj < 2; sj++ { 1362 a := NewDense(3, 3, []float64{ 1363 1, 2, 3, 1364 4, 5, 6, 1365 7, 8, 9, 1366 }) 1367 src := a.Slice(si, si+2, sj, sj+2) 1368 want := DenseCopyOf(src) 1369 got := a.Slice(di, di+2, dj, dj+2).(*Dense) 1370 1371 if trans { 1372 panicked, _ := panics(func() { got.Copy(src.T()) }) 1373 if !panicked { 1374 t.Errorf("expected panic for transpose aliased copy with offsets dst(%d,%d) src(%d,%d):\ngot:\n%v\nwant:\n%v", 1375 di, dj, si, sj, Formatted(got), Formatted(want), 1376 ) 1377 } 1378 continue 1379 } 1380 1381 got.Copy(src) 1382 if !Equal(got, want) { 1383 t.Errorf("unexpected aliased copy result with offsets dst(%d,%d) src(%d,%d):\ngot:\n%v\nwant:\n%v", 1384 di, dj, si, sj, Formatted(got), Formatted(want), 1385 ) 1386 } 1387 } 1388 } 1389 } 1390 } 1391 } 1392 } 1393 1394 func TestDenseCopyVecDenseAlias(t *testing.T) { 1395 t.Parallel() 1396 for _, horiz := range []bool{false, true} { 1397 for do := 0; do < 2; do++ { 1398 for di := 0; di < 3; di++ { 1399 for si := 0; si < 3; si++ { 1400 a := NewDense(3, 3, []float64{ 1401 1, 2, 3, 1402 4, 5, 6, 1403 7, 8, 9, 1404 }) 1405 var src Vector 1406 var want *Dense 1407 if horiz { 1408 src = a.RowView(si) 1409 want = DenseCopyOf(a.Slice(si, si+1, 0, 2)) 1410 } else { 1411 src = a.ColView(si) 1412 want = DenseCopyOf(a.Slice(0, 2, si, si+1)) 1413 } 1414 1415 var got *Dense 1416 if horiz { 1417 got = a.Slice(di, di+1, do, do+2).(*Dense) 1418 got.Copy(src.T()) 1419 } else { 1420 got = a.Slice(do, do+2, di, di+1).(*Dense) 1421 got.Copy(src) 1422 } 1423 1424 if !Equal(got, want) { 1425 t.Errorf("unexpected aliased copy result with offsets dst(%d) src(%d):\ngot:\n%v\nwant:\n%v", 1426 di, si, Formatted(got), Formatted(want), 1427 ) 1428 } 1429 } 1430 } 1431 } 1432 } 1433 } 1434 1435 func identity(r, c int, v float64) float64 { return v } 1436 1437 func TestDenseApply(t *testing.T) { 1438 t.Parallel() 1439 for i, test := range []struct { 1440 a, want [][]float64 1441 fn func(r, c int, v float64) float64 1442 }{ 1443 { 1444 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1445 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1446 identity, 1447 }, 1448 { 1449 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1450 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1451 identity, 1452 }, 1453 { 1454 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1455 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1456 identity, 1457 }, 1458 { 1459 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1460 [][]float64{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}, 1461 identity, 1462 }, 1463 { 1464 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1465 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1466 identity, 1467 }, 1468 { 1469 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1470 [][]float64{{2, 4, 6}, {8, 10, 12}}, 1471 func(r, c int, v float64) float64 { return v * 2 }, 1472 }, 1473 { 1474 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1475 [][]float64{{0, 2, 0}, {0, 5, 0}}, 1476 func(r, c int, v float64) float64 { 1477 if c == 1 { 1478 return v 1479 } 1480 return 0 1481 }, 1482 }, 1483 { 1484 [][]float64{{1, 2, 3}, {4, 5, 6}}, 1485 [][]float64{{0, 0, 0}, {4, 5, 6}}, 1486 func(r, c int, v float64) float64 { 1487 if r == 1 { 1488 return v 1489 } 1490 return 0 1491 }, 1492 }, 1493 } { 1494 a := NewDense(flatten(test.a)) 1495 want := NewDense(flatten(test.want)) 1496 1497 var got Dense 1498 1499 for j := 0; j < 2; j++ { 1500 got.Apply(test.fn, a) 1501 if !Equal(&got, want) { 1502 t.Errorf("unexpected result for test %d iteration %d: got: %v want: %v", i, j, got.mat.Data, want.mat.Data) 1503 } 1504 } 1505 } 1506 1507 for _, fn := range []func(r, c int, v float64) float64{ 1508 identity, 1509 func(r, c int, v float64) float64 { 1510 if r < c { 1511 return v 1512 } 1513 return -v 1514 }, 1515 func(r, c int, v float64) float64 { 1516 if r%2 == 0 && c%2 == 0 { 1517 return v 1518 } 1519 return -v 1520 }, 1521 func(_, _ int, v float64) float64 { return v * v }, 1522 func(_, _ int, v float64) float64 { return -v }, 1523 } { 1524 method := func(receiver, x Matrix) { 1525 type Applier interface { 1526 Apply(func(r, c int, v float64) float64, Matrix) 1527 } 1528 rd := receiver.(Applier) 1529 rd.Apply(fn, x) 1530 } 1531 denseComparison := func(receiver, x *Dense) { 1532 receiver.Apply(fn, x) 1533 } 1534 testOneInput(t, "Apply", &Dense{}, method, denseComparison, isAnyType, isAnySize, 0) 1535 } 1536 } 1537 1538 func TestDenseClone(t *testing.T) { 1539 t.Parallel() 1540 for i, test := range []struct { 1541 a [][]float64 1542 i, j int 1543 v float64 1544 }{ 1545 { 1546 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1547 1, 1, 1548 1, 1549 }, 1550 { 1551 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1552 0, 0, 1553 0, 1554 }, 1555 } { 1556 a := NewDense(flatten(test.a)) 1557 b := *a 1558 a.CloneFrom(a) 1559 a.Set(test.i, test.j, test.v) 1560 1561 if Equal(&b, a) { 1562 t.Errorf("unexpected mirror of write to cloned matrix for test %d: %v cloned and altered = %v", 1563 i, a, &b) 1564 } 1565 } 1566 } 1567 1568 // TODO(kortschak) Roll this into testOneInput when it exists. 1569 func TestDenseCopyPanic(t *testing.T) { 1570 t.Parallel() 1571 for _, a := range []*Dense{ 1572 {}, 1573 {mat: blas64.General{Rows: 1}}, 1574 {mat: blas64.General{Cols: 1}}, 1575 } { 1576 var rows, cols int 1577 m := NewDense(1, 1, nil) 1578 panicked, message := panics(func() { rows, cols = m.Copy(a) }) 1579 if panicked { 1580 t.Errorf("unexpected panic: %v", message) 1581 } 1582 if rows != 0 { 1583 t.Errorf("unexpected rows: got: %d want: 0", rows) 1584 } 1585 if cols != 0 { 1586 t.Errorf("unexpected cols: got: %d want: 0", cols) 1587 } 1588 } 1589 } 1590 1591 func TestDenseStack(t *testing.T) { 1592 t.Parallel() 1593 for i, test := range []struct { 1594 a, b, e [][]float64 1595 }{ 1596 { 1597 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1598 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1599 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1600 }, 1601 { 1602 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1603 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1604 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1605 }, 1606 { 1607 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1608 [][]float64{{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, 1609 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, 1610 }, 1611 } { 1612 a := NewDense(flatten(test.a)) 1613 b := NewDense(flatten(test.b)) 1614 1615 var s Dense 1616 s.Stack(a, b) 1617 1618 if !Equal(&s, NewDense(flatten(test.e))) { 1619 t.Errorf("unexpected result for Stack test %d: %v stack %v = %v", i, a, b, s) 1620 } 1621 } 1622 1623 method := func(receiver, a, b Matrix) { 1624 type Stacker interface { 1625 Stack(a, b Matrix) 1626 } 1627 rd := receiver.(Stacker) 1628 rd.Stack(a, b) 1629 } 1630 denseComparison := func(receiver, a, b *Dense) { 1631 receiver.Stack(a, b) 1632 } 1633 testTwoInput(t, "Stack", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameWidth, 0) 1634 } 1635 1636 func TestDenseAugment(t *testing.T) { 1637 t.Parallel() 1638 for i, test := range []struct { 1639 a, b, e [][]float64 1640 }{ 1641 { 1642 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1643 [][]float64{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, 1644 [][]float64{{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}}, 1645 }, 1646 { 1647 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1648 [][]float64{{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, 1649 [][]float64{{1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}}, 1650 }, 1651 { 1652 [][]float64{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, 1653 [][]float64{{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, 1654 [][]float64{{1, 0, 0, 0, 1, 0}, {0, 1, 0, 0, 0, 1}, {0, 0, 1, 1, 0, 0}}, 1655 }, 1656 } { 1657 a := NewDense(flatten(test.a)) 1658 b := NewDense(flatten(test.b)) 1659 1660 var s Dense 1661 s.Augment(a, b) 1662 1663 if !Equal(&s, NewDense(flatten(test.e))) { 1664 t.Errorf("unexpected result for Augment test %d: %v augment %v = %v", i, a, b, s) 1665 } 1666 } 1667 1668 method := func(receiver, a, b Matrix) { 1669 type Augmenter interface { 1670 Augment(a, b Matrix) 1671 } 1672 rd := receiver.(Augmenter) 1673 rd.Augment(a, b) 1674 } 1675 denseComparison := func(receiver, a, b *Dense) { 1676 receiver.Augment(a, b) 1677 } 1678 testTwoInput(t, "Augment", &Dense{}, method, denseComparison, legalTypesAll, legalSizeSameHeight, 0) 1679 } 1680 1681 func TestDenseRankOne(t *testing.T) { 1682 t.Parallel() 1683 for i, test := range []struct { 1684 x []float64 1685 y []float64 1686 m [][]float64 1687 alpha float64 1688 }{ 1689 { 1690 x: []float64{5}, 1691 y: []float64{10}, 1692 m: [][]float64{{2}}, 1693 alpha: -3, 1694 }, 1695 { 1696 x: []float64{5, 6, 1}, 1697 y: []float64{10}, 1698 m: [][]float64{{2}, {-3}, {5}}, 1699 alpha: -3, 1700 }, 1701 1702 { 1703 x: []float64{5}, 1704 y: []float64{10, 15, 8}, 1705 m: [][]float64{{2, -3, 5}}, 1706 alpha: -3, 1707 }, 1708 { 1709 x: []float64{1, 5}, 1710 y: []float64{10, 15}, 1711 m: [][]float64{ 1712 {2, -3}, 1713 {4, -1}, 1714 }, 1715 alpha: -3, 1716 }, 1717 { 1718 x: []float64{2, 3, 9}, 1719 y: []float64{8, 9}, 1720 m: [][]float64{ 1721 {2, 3}, 1722 {4, 5}, 1723 {6, 7}, 1724 }, 1725 alpha: -3, 1726 }, 1727 { 1728 x: []float64{2, 3}, 1729 y: []float64{8, 9, 9}, 1730 m: [][]float64{ 1731 {2, 3, 6}, 1732 {4, 5, 7}, 1733 }, 1734 alpha: -3, 1735 }, 1736 } { 1737 want := &Dense{} 1738 xm := NewDense(len(test.x), 1, test.x) 1739 ym := NewDense(1, len(test.y), test.y) 1740 1741 want.Mul(xm, ym) 1742 want.Scale(test.alpha, want) 1743 want.Add(want, NewDense(flatten(test.m))) 1744 1745 a := NewDense(flatten(test.m)) 1746 m := &Dense{} 1747 // Check with a new matrix 1748 m.RankOne(a, test.alpha, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) 1749 if !Equal(m, want) { 1750 t.Errorf("unexpected result for RankOne test %d iteration 0: got: %+v want: %+v", i, m, want) 1751 } 1752 // Check with the same matrix 1753 a.RankOne(a, test.alpha, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) 1754 if !Equal(a, want) { 1755 t.Errorf("unexpected result for RankOne test %d iteration 1: got: %+v want: %+v", i, m, want) 1756 } 1757 } 1758 } 1759 1760 func TestDenseOuter(t *testing.T) { 1761 t.Parallel() 1762 for i, test := range []struct { 1763 x []float64 1764 y []float64 1765 }{ 1766 { 1767 x: []float64{5}, 1768 y: []float64{10}, 1769 }, 1770 { 1771 x: []float64{5, 6, 1}, 1772 y: []float64{10}, 1773 }, 1774 1775 { 1776 x: []float64{5}, 1777 y: []float64{10, 15, 8}, 1778 }, 1779 { 1780 x: []float64{1, 5}, 1781 y: []float64{10, 15}, 1782 }, 1783 { 1784 x: []float64{2, 3, 9}, 1785 y: []float64{8, 9}, 1786 }, 1787 { 1788 x: []float64{2, 3}, 1789 y: []float64{8, 9, 9}, 1790 }, 1791 } { 1792 for _, f := range []float64{0.5, 1, 3} { 1793 want := &Dense{} 1794 xm := NewDense(len(test.x), 1, test.x) 1795 ym := NewDense(1, len(test.y), test.y) 1796 1797 want.Mul(xm, ym) 1798 want.Scale(f, want) 1799 1800 var m Dense 1801 for j := 0; j < 2; j++ { 1802 // Check with a new matrix - and then again. 1803 m.Outer(f, NewVecDense(len(test.x), test.x), NewVecDense(len(test.y), test.y)) 1804 if !Equal(&m, want) { 1805 t.Errorf("unexpected result for Outer test %d iteration %d scale %v: got: %+v want: %+v", i, j, f, m, want) 1806 } 1807 } 1808 } 1809 } 1810 1811 for _, alpha := range []float64{0, 1, -1, 2.3, -2.3} { 1812 method := func(receiver, x, y Matrix) { 1813 type outerer interface { 1814 Outer(alpha float64, x, y Vector) 1815 } 1816 m := receiver.(outerer) 1817 m.Outer(alpha, x.(Vector), y.(Vector)) 1818 } 1819 denseComparison := func(receiver, x, y *Dense) { 1820 receiver.Mul(x, y.T()) 1821 receiver.Scale(alpha, receiver) 1822 } 1823 testTwoInput(t, "Outer", &Dense{}, method, denseComparison, legalTypesVectorVector, legalSizeVector, 1e-12) 1824 } 1825 } 1826 1827 func TestDenseInverse(t *testing.T) { 1828 t.Parallel() 1829 for i, test := range []struct { 1830 a Matrix 1831 want Matrix // nil indicates that a is singular. 1832 tol float64 1833 }{ 1834 { 1835 a: NewDense(3, 3, []float64{ 1836 8, 1, 6, 1837 3, 5, 7, 1838 4, 9, 2, 1839 }), 1840 want: NewDense(3, 3, []float64{ 1841 0.147222222222222, -0.144444444444444, 0.063888888888889, 1842 -0.061111111111111, 0.022222222222222, 0.105555555555556, 1843 -0.019444444444444, 0.188888888888889, -0.102777777777778, 1844 }), 1845 tol: 1e-14, 1846 }, 1847 { 1848 a: NewDense(3, 3, []float64{ 1849 8, 1, 6, 1850 3, 5, 7, 1851 4, 9, 2, 1852 }).T(), 1853 want: NewDense(3, 3, []float64{ 1854 0.147222222222222, -0.144444444444444, 0.063888888888889, 1855 -0.061111111111111, 0.022222222222222, 0.105555555555556, 1856 -0.019444444444444, 0.188888888888889, -0.102777777777778, 1857 }).T(), 1858 tol: 1e-14, 1859 }, 1860 1861 // This case does not fail, but we do not guarantee that. The success 1862 // is because the receiver and the input are aligned in the call to 1863 // inverse. If there was a misalignment, the result would likely be 1864 // incorrect and no shadowing panic would occur. 1865 { 1866 a: asBasicMatrix(NewDense(3, 3, []float64{ 1867 8, 1, 6, 1868 3, 5, 7, 1869 4, 9, 2, 1870 })), 1871 want: NewDense(3, 3, []float64{ 1872 0.147222222222222, -0.144444444444444, 0.063888888888889, 1873 -0.061111111111111, 0.022222222222222, 0.105555555555556, 1874 -0.019444444444444, 0.188888888888889, -0.102777777777778, 1875 }), 1876 tol: 1e-14, 1877 }, 1878 1879 // The following case fails as it does not follow the shadowing rules. 1880 // Specifically, the test extracts the underlying *Dense, and uses 1881 // it as a receiver with the basicMatrix as input. The basicMatrix type 1882 // allows shadowing of the input data without providing the Raw method 1883 // required for detection of shadowing. 1884 // 1885 // We specifically state we do not check this case. 1886 // 1887 // { 1888 // a: asBasicMatrix(NewDense(3, 3, []float64{ 1889 // 8, 1, 6, 1890 // 3, 5, 7, 1891 // 4, 9, 2, 1892 // })).T(), 1893 // want: NewDense(3, 3, []float64{ 1894 // 0.147222222222222, -0.144444444444444, 0.063888888888889, 1895 // -0.061111111111111, 0.022222222222222, 0.105555555555556, 1896 // -0.019444444444444, 0.188888888888889, -0.102777777777778, 1897 // }).T(), 1898 // tol: 1e-14, 1899 // }, 1900 1901 { 1902 a: NewDense(4, 4, []float64{ 1903 5, 2, 8, 7, 1904 4, 5, 8, 2, 1905 8, 5, 3, 2, 1906 8, 7, 7, 5, 1907 }), 1908 want: NewDense(4, 4, []float64{ 1909 0.100548446069470, 0.021937842778793, 0.334552102376599, -0.283363802559415, 1910 -0.226691042047532, -0.067641681901280, -0.281535648994515, 0.457038391224863, 1911 0.080438756855576, 0.217550274223035, 0.067641681901280, -0.226691042047532, 1912 0.043875685557587, -0.244972577696527, -0.235831809872029, 0.330895795246801, 1913 }), 1914 tol: 1e-14, 1915 }, 1916 1917 // Tests with singular matrix. 1918 { 1919 a: NewDense(1, 1, []float64{ 1920 0, 1921 }), 1922 }, 1923 { 1924 a: NewDense(2, 2, []float64{ 1925 0, 0, 1926 0, 0, 1927 }), 1928 }, 1929 { 1930 a: NewDense(2, 2, []float64{ 1931 0, 0, 1932 0, 1, 1933 }), 1934 }, 1935 { 1936 a: NewDense(3, 3, []float64{ 1937 0, 0, 0, 1938 0, 0, 0, 1939 0, 0, 0, 1940 }), 1941 }, 1942 { 1943 a: NewDense(4, 4, []float64{ 1944 0, 0, 0, 0, 1945 0, 0, 0, 0, 1946 0, 0, 0, 0, 1947 0, 0, 0, 0, 1948 }), 1949 }, 1950 { 1951 a: NewDense(4, 4, []float64{ 1952 0, 0, 0, 0, 1953 0, 0, 0, 0, 1954 0, 0, 20, 20, 1955 0, 0, 20, 20, 1956 }), 1957 }, 1958 { 1959 a: NewDense(4, 4, []float64{ 1960 0, 1, 0, 0, 1961 0, 0, 1, 0, 1962 0, 0, 0, 1, 1963 0, 0, 0, 0, 1964 }), 1965 }, 1966 { 1967 a: NewDense(4, 4, []float64{ 1968 1, 1, 1, 1, 1969 1, 1, 1, 1, 1970 1, 1, 1, 1, 1971 1, 1, 1, 1, 1972 }), 1973 }, 1974 { 1975 a: NewDense(5, 5, []float64{ 1976 0, 1, 0, 0, 0, 1977 4, 0, 2, 0, 0, 1978 0, 3, 0, 3, 0, 1979 0, 0, 2, 0, 4, 1980 0, 0, 0, 1, 0, 1981 }), 1982 }, 1983 { 1984 a: NewDense(5, 5, []float64{ 1985 4, -1, -1, -1, -1, 1986 -1, 4, -1, -1, -1, 1987 -1, -1, 4, -1, -1, 1988 -1, -1, -1, 4, -1, 1989 -1, -1, -1, -1, 4, 1990 }), 1991 }, 1992 { 1993 a: NewDense(5, 5, []float64{ 1994 2, -1, 0, 0, -1, 1995 -1, 2, -1, 0, 0, 1996 0, -1, 2, -1, 0, 1997 0, 0, -1, 2, -1, 1998 -1, 0, 0, -1, 2, 1999 }), 2000 }, 2001 { 2002 a: NewDense(5, 5, []float64{ 2003 1, 2, 3, 5, 8, 2004 2, 3, 5, 8, 13, 2005 3, 5, 8, 13, 21, 2006 5, 8, 13, 21, 34, 2007 8, 13, 21, 34, 55, 2008 }), 2009 }, 2010 { 2011 a: NewDense(8, 8, []float64{ 2012 611, 196, -192, 407, -8, -52, -49, 29, 2013 196, 899, 113, -192, -71, -43, -8, -44, 2014 -192, 113, 899, 196, 61, 49, 8, 52, 2015 407, -192, 196, 611, 8, 44, 59, -23, 2016 -8, -71, 61, 8, 411, -599, 208, 208, 2017 -52, -43, 49, 44, -599, 411, 208, 208, 2018 -49, -8, 8, 59, 208, 208, 99, -911, 2019 29, -44, 52, -23, 208, 208, -911, 99, 2020 }), 2021 }, 2022 } { 2023 var got Dense 2024 err := got.Inverse(test.a) 2025 if test.want == nil { 2026 if err == nil { 2027 t.Errorf("Case %d: expected error for singular matrix", i) 2028 } 2029 continue 2030 } 2031 if err != nil { 2032 t.Errorf("Case %d: unexpected error: %v", i, err) 2033 continue 2034 } 2035 if !equalApprox(&got, test.want, test.tol, false) { 2036 t.Errorf("Case %d, inverse mismatch.", i) 2037 } 2038 var m Dense 2039 m.Mul(&got, test.a) 2040 r, _ := test.a.Dims() 2041 d := make([]float64, r*r) 2042 for i := 0; i < r*r; i += r + 1 { 2043 d[i] = 1 2044 } 2045 eye := NewDense(r, r, d) 2046 if !equalApprox(eye, &m, 1e-14, false) { 2047 t.Errorf("Case %d, A^-1 * A != I", i) 2048 } 2049 2050 var tmp Dense 2051 tmp.CloneFrom(test.a) 2052 aU, transposed := untranspose(test.a) 2053 if transposed { 2054 switch aU := aU.(type) { 2055 case *Dense: 2056 err = aU.Inverse(test.a) 2057 case *basicMatrix: 2058 err = (*Dense)(aU).Inverse(test.a) 2059 default: 2060 continue 2061 } 2062 m.Mul(aU, &tmp) 2063 } else { 2064 switch a := test.a.(type) { 2065 case *Dense: 2066 err = a.Inverse(test.a) 2067 m.Mul(a, &tmp) 2068 case *basicMatrix: 2069 err = (*Dense)(a).Inverse(test.a) 2070 m.Mul(a, &tmp) 2071 default: 2072 continue 2073 } 2074 } 2075 if err != nil { 2076 t.Errorf("Error computing inverse: %v", err) 2077 } 2078 if !equalApprox(eye, &m, 1e-14, false) { 2079 t.Errorf("Case %d, A^-1 * A != I", i) 2080 fmt.Println(Formatted(&m)) 2081 } 2082 } 2083 2084 // Randomized tests 2085 const tol = 1e-16 2086 rnd := rand.New(rand.NewSource(1)) 2087 for _, recvSameAsA := range []bool{false, true} { 2088 for _, trans := range []bool{false, true} { 2089 if trans && recvSameAsA { 2090 // Transposed argument cannot be a receiver. 2091 continue 2092 } 2093 for _, n := range []int{1, 2, 3, 5, 10, 50, 100} { 2094 name := fmt.Sprintf("n=%d,recvSameAsA=%v,trans=%v", n, recvSameAsA, trans) 2095 2096 // Generate the contents of a random dense matrix. 2097 data := make([]float64, n*n) 2098 for i := range data { 2099 data[i] = rnd.NormFloat64() 2100 } 2101 2102 var a Matrix 2103 var aInv Dense 2104 if recvSameAsA { 2105 aInv = *NewDense(n, n, data) 2106 a = &aInv 2107 } else { 2108 if trans { 2109 a = NewDense(n, n, data).T() 2110 } else { 2111 a = asBasicMatrix(NewDense(n, n, data)) 2112 } 2113 2114 } 2115 var aOrig Dense 2116 aOrig.CloneFrom(a) 2117 2118 err := aInv.Inverse(a) 2119 if err != nil { 2120 t.Errorf("%v: unexpected failure of Inverse, %v", name, err) 2121 continue 2122 } 2123 2124 // Compute the residual |I - A^{-1} * A| / (N * |A| * |A^{-1}). 2125 var aaInv Dense 2126 aaInv.Mul(&aInv, &aOrig) 2127 for i := 0; i < n; i++ { 2128 aaInv.Set(i, i, 1-aaInv.At(i, i)) 2129 } 2130 resid := Norm(&aaInv, 1) / (float64(n) * Norm(&aOrig, 1) * Norm(&aInv, 1)) 2131 if resid > tol { 2132 t.Errorf("%v: A*A^{-1} is not identity, resid=%v,want<=%v", name, resid, tol) 2133 } 2134 } 2135 } 2136 } 2137 } 2138 2139 func TestDensePermutation(t *testing.T) { 2140 for n := 1; n <= 6; n++ { 2141 for idx, perm := range combin.Permutations(n, n) { 2142 want := NewDense(n, n, nil) 2143 for i := 0; i < n; i++ { 2144 want.Set(i, perm[i], 1) 2145 } 2146 2147 var got Dense 2148 got.Permutation(n, perm) 2149 if !Equal(&got, want) { 2150 t.Errorf("n=%d,idx=%d: unexpected permutation matrix\n got=%v\nwant=%v", 2151 n, idx, Formatted(&got, Prefix(" ")), Formatted(want, Prefix(" "))) 2152 } 2153 } 2154 } 2155 } 2156 2157 func TestDensePermuteRows(t *testing.T) { 2158 rnd := rand.New(rand.NewSource(1)) 2159 for m := 1; m <= 5; m++ { 2160 for idx, perm := range combin.Permutations(m, m) { 2161 // Construct a permutation matrix P from perm. 2162 p := NewDense(m, m, nil) 2163 for i := 0; i < m; i++ { 2164 p.Set(i, perm[i], 1) 2165 } 2166 2167 for n := 1; n <= 5; n++ { 2168 name := fmt.Sprintf("m=%d,n=%d,idx=%d", m, n, idx) 2169 2170 // Generate a random m×n matrix A. 2171 a := NewDense(m, n, nil) 2172 for i := 0; i < m; i++ { 2173 for j := 0; j < n; j++ { 2174 a.Set(i, j, rnd.Float64()) 2175 } 2176 } 2177 2178 // Compute P*A. 2179 var want Dense 2180 want.Mul(p, a) 2181 // Permute rows of A by applying perm. 2182 var got Dense 2183 got.CloneFrom(a) 2184 got.PermuteRows(perm, false) 2185 if !Equal(&got, &want) { 2186 t.Errorf("%s: unexpected result\n got=%v\nwant=%v", 2187 name, Formatted(&got, Prefix(" ")), Formatted(&want, Prefix(" "))) 2188 } 2189 2190 // Compute Pᵀ*A. 2191 want.Mul(p.T(), a) 2192 // Permute rows of A by applying inverse perm. 2193 got.Copy(a) 2194 got.PermuteRows(perm, true) 2195 if !Equal(&got, &want) { 2196 t.Errorf("%s: unexpected result with inverse permutation\n got=%v\nwant=%v", 2197 name, Formatted(&got, Prefix(" ")), Formatted(&want, Prefix(" "))) 2198 } 2199 2200 // Permute rows of A by applying perm and inverse perm. 2201 got.Copy(a) 2202 got.PermuteRows(perm, false) 2203 got.PermuteRows(perm, true) 2204 if !Equal(&got, a) { 2205 t.Errorf("%s: original A not recovered\n got=%v\nwant=%v", 2206 name, Formatted(&got, Prefix(" ")), Formatted(a, Prefix(" "))) 2207 } 2208 } 2209 } 2210 } 2211 } 2212 2213 func TestDensePermuteCols(t *testing.T) { 2214 rnd := rand.New(rand.NewSource(1)) 2215 for n := 1; n <= 5; n++ { 2216 for idx, perm := range combin.Permutations(n, n) { 2217 // Construct a permutation matrix P from perm. 2218 p := NewDense(n, n, nil) 2219 for j := 0; j < n; j++ { 2220 p.Set(perm[j], j, 1) 2221 } 2222 2223 for m := 1; m <= 5; m++ { 2224 name := fmt.Sprintf("m=%d,n=%d,idx=%d", m, n, idx) 2225 2226 // Generate a random m×n matrix A. 2227 a := NewDense(m, n, nil) 2228 for i := 0; i < m; i++ { 2229 for j := 0; j < n; j++ { 2230 a.Set(i, j, rnd.Float64()) 2231 } 2232 } 2233 2234 // Compute A*P. 2235 var want Dense 2236 want.Mul(a, p) 2237 // Permute columns of A by applying perm. 2238 var got Dense 2239 got.CloneFrom(a) 2240 got.PermuteCols(perm, false) 2241 if !Equal(&got, &want) { 2242 t.Errorf("%s: unexpected result\n got=%v\nwant=%v", 2243 name, Formatted(&got, Prefix(" ")), Formatted(&want, Prefix(" "))) 2244 } 2245 2246 // Compute A*Pᵀ. 2247 want.Mul(a, p.T()) 2248 // Permute columns of A by applying inverse perm. 2249 got.Copy(a) 2250 got.PermuteCols(perm, true) 2251 if !Equal(&got, &want) { 2252 t.Errorf("%s: unexpected result with inverse permutation\n got=%v\nwant=%v", 2253 name, Formatted(&got, Prefix(" ")), Formatted(&want, Prefix(" "))) 2254 } 2255 2256 // Permute columns of A by applying perm and inverse perm. 2257 got.Copy(a) 2258 got.PermuteCols(perm, false) 2259 got.PermuteCols(perm, true) 2260 if !Equal(&got, a) { 2261 t.Errorf("%s: original A not recovered\n got=%v\nwant=%v", 2262 name, Formatted(&got, Prefix(" ")), Formatted(a, Prefix(" "))) 2263 } 2264 } 2265 } 2266 } 2267 } 2268 2269 var ( 2270 wd *Dense 2271 ) 2272 2273 func BenchmarkMulDense100Half(b *testing.B) { denseMulBench(b, 100, 0.5) } 2274 func BenchmarkMulDense100Tenth(b *testing.B) { denseMulBench(b, 100, 0.1) } 2275 func BenchmarkMulDense1000Half(b *testing.B) { denseMulBench(b, 1000, 0.5) } 2276 func BenchmarkMulDense1000Tenth(b *testing.B) { denseMulBench(b, 1000, 0.1) } 2277 func BenchmarkMulDense1000Hundredth(b *testing.B) { denseMulBench(b, 1000, 0.01) } 2278 func BenchmarkMulDense1000Thousandth(b *testing.B) { denseMulBench(b, 1000, 0.001) } 2279 func denseMulBench(b *testing.B, size int, rho float64) { 2280 src := rand.NewSource(1) 2281 b.StopTimer() 2282 a, _ := randDense(size, rho, src) 2283 d, _ := randDense(size, rho, src) 2284 b.StartTimer() 2285 for i := 0; i < b.N; i++ { 2286 var n Dense 2287 n.Mul(a, d) 2288 wd = &n 2289 } 2290 } 2291 2292 func BenchmarkPreMulDense100Half(b *testing.B) { densePreMulBench(b, 100, 0.5) } 2293 func BenchmarkPreMulDense100Tenth(b *testing.B) { densePreMulBench(b, 100, 0.1) } 2294 func BenchmarkPreMulDense1000Half(b *testing.B) { densePreMulBench(b, 1000, 0.5) } 2295 func BenchmarkPreMulDense1000Tenth(b *testing.B) { densePreMulBench(b, 1000, 0.1) } 2296 func BenchmarkPreMulDense1000Hundredth(b *testing.B) { densePreMulBench(b, 1000, 0.01) } 2297 func BenchmarkPreMulDense1000Thousandth(b *testing.B) { densePreMulBench(b, 1000, 0.001) } 2298 func densePreMulBench(b *testing.B, size int, rho float64) { 2299 src := rand.NewSource(1) 2300 b.StopTimer() 2301 a, _ := randDense(size, rho, src) 2302 d, _ := randDense(size, rho, src) 2303 wd = NewDense(size, size, nil) 2304 b.StartTimer() 2305 for i := 0; i < b.N; i++ { 2306 wd.Mul(a, d) 2307 } 2308 } 2309 2310 func BenchmarkDenseRow10(b *testing.B) { rowDenseBench(b, 10) } 2311 func BenchmarkDenseRow100(b *testing.B) { rowDenseBench(b, 100) } 2312 func BenchmarkDenseRow1000(b *testing.B) { rowDenseBench(b, 1000) } 2313 2314 func rowDenseBench(b *testing.B, size int) { 2315 src := rand.NewSource(1) 2316 a, _ := randDense(size, 1, src) 2317 _, c := a.Dims() 2318 dst := make([]float64, c) 2319 2320 b.ResetTimer() 2321 for i := 0; i < b.N; i++ { 2322 Row(dst, 0, a) 2323 } 2324 } 2325 2326 func BenchmarkDenseExp10(b *testing.B) { expDenseBench(b, 10) } 2327 func BenchmarkDenseExp100(b *testing.B) { expDenseBench(b, 100) } 2328 func BenchmarkDenseExp1000(b *testing.B) { expDenseBench(b, 1000) } 2329 2330 func expDenseBench(b *testing.B, size int) { 2331 src := rand.NewSource(1) 2332 a, _ := randDense(size, 1, src) 2333 2334 b.ResetTimer() 2335 var m Dense 2336 for i := 0; i < b.N; i++ { 2337 m.Exp(a) 2338 } 2339 } 2340 2341 func BenchmarkDensePow10_3(b *testing.B) { powDenseBench(b, 10, 3) } 2342 func BenchmarkDensePow100_3(b *testing.B) { powDenseBench(b, 100, 3) } 2343 func BenchmarkDensePow1000_3(b *testing.B) { powDenseBench(b, 1000, 3) } 2344 func BenchmarkDensePow10_4(b *testing.B) { powDenseBench(b, 10, 4) } 2345 func BenchmarkDensePow100_4(b *testing.B) { powDenseBench(b, 100, 4) } 2346 func BenchmarkDensePow1000_4(b *testing.B) { powDenseBench(b, 1000, 4) } 2347 func BenchmarkDensePow10_5(b *testing.B) { powDenseBench(b, 10, 5) } 2348 func BenchmarkDensePow100_5(b *testing.B) { powDenseBench(b, 100, 5) } 2349 func BenchmarkDensePow1000_5(b *testing.B) { powDenseBench(b, 1000, 5) } 2350 func BenchmarkDensePow10_6(b *testing.B) { powDenseBench(b, 10, 6) } 2351 func BenchmarkDensePow100_6(b *testing.B) { powDenseBench(b, 100, 6) } 2352 func BenchmarkDensePow1000_6(b *testing.B) { powDenseBench(b, 1000, 6) } 2353 func BenchmarkDensePow10_7(b *testing.B) { powDenseBench(b, 10, 7) } 2354 func BenchmarkDensePow100_7(b *testing.B) { powDenseBench(b, 100, 7) } 2355 func BenchmarkDensePow1000_7(b *testing.B) { powDenseBench(b, 1000, 7) } 2356 func BenchmarkDensePow10_8(b *testing.B) { powDenseBench(b, 10, 8) } 2357 func BenchmarkDensePow100_8(b *testing.B) { powDenseBench(b, 100, 8) } 2358 func BenchmarkDensePow1000_8(b *testing.B) { powDenseBench(b, 1000, 8) } 2359 func BenchmarkDensePow10_9(b *testing.B) { powDenseBench(b, 10, 9) } 2360 func BenchmarkDensePow100_9(b *testing.B) { powDenseBench(b, 100, 9) } 2361 func BenchmarkDensePow1000_9(b *testing.B) { powDenseBench(b, 1000, 9) } 2362 2363 func powDenseBench(b *testing.B, size, n int) { 2364 src := rand.NewSource(1) 2365 a, _ := randDense(size, 1, src) 2366 2367 b.ResetTimer() 2368 var m Dense 2369 for i := 0; i < b.N; i++ { 2370 m.Pow(a, n) 2371 } 2372 } 2373 2374 func BenchmarkDenseMulTransDense100Half(b *testing.B) { denseMulTransBench(b, 100, 0.5) } 2375 func BenchmarkDenseMulTransDense100Tenth(b *testing.B) { denseMulTransBench(b, 100, 0.1) } 2376 func BenchmarkDenseMulTransDense1000Half(b *testing.B) { denseMulTransBench(b, 1000, 0.5) } 2377 func BenchmarkDenseMulTransDense1000Tenth(b *testing.B) { denseMulTransBench(b, 1000, 0.1) } 2378 func BenchmarkDenseMulTransDense1000Hundredth(b *testing.B) { denseMulTransBench(b, 1000, 0.01) } 2379 func BenchmarkDenseMulTransDense1000Thousandth(b *testing.B) { denseMulTransBench(b, 1000, 0.001) } 2380 func denseMulTransBench(b *testing.B, size int, rho float64) { 2381 src := rand.NewSource(1) 2382 b.StopTimer() 2383 a, _ := randDense(size, rho, src) 2384 d, _ := randDense(size, rho, src) 2385 b.StartTimer() 2386 for i := 0; i < b.N; i++ { 2387 var n Dense 2388 n.Mul(a, d.T()) 2389 wd = &n 2390 } 2391 } 2392 2393 func BenchmarkDenseMulTransDenseSym100Half(b *testing.B) { denseMulTransSymBench(b, 100, 0.5) } 2394 func BenchmarkDenseMulTransDenseSym100Tenth(b *testing.B) { denseMulTransSymBench(b, 100, 0.1) } 2395 func BenchmarkDenseMulTransDenseSym1000Half(b *testing.B) { denseMulTransSymBench(b, 1000, 0.5) } 2396 func BenchmarkDenseMulTransDenseSym1000Tenth(b *testing.B) { denseMulTransSymBench(b, 1000, 0.1) } 2397 func BenchmarkDenseMulTransDenseSym1000Hundredth(b *testing.B) { denseMulTransSymBench(b, 1000, 0.01) } 2398 func BenchmarkDenseMulTransDenseSym1000Thousandth(b *testing.B) { 2399 denseMulTransSymBench(b, 1000, 0.001) 2400 } 2401 func denseMulTransSymBench(b *testing.B, size int, rho float64) { 2402 src := rand.NewSource(1) 2403 b.StopTimer() 2404 a, _ := randDense(size, rho, src) 2405 b.StartTimer() 2406 for i := 0; i < b.N; i++ { 2407 var n Dense 2408 n.Mul(a, a.T()) 2409 wd = &n 2410 } 2411 } 2412 2413 func BenchmarkDenseSum1000(b *testing.B) { denseSumBench(b, 1000) } 2414 2415 var denseSumForBench float64 2416 2417 func denseSumBench(b *testing.B, size int) { 2418 src := rand.NewSource(1) 2419 a, _ := randDense(size, 1.0, src) 2420 b.ResetTimer() 2421 for i := 0; i < b.N; i++ { 2422 denseSumForBench = Sum(a) 2423 } 2424 }