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