├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── matrix.go └── matrix_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.0 4 | - 1.1 5 | - 1.2 6 | - 1.3 7 | script: go test 8 | install: 9 | - export PATH=$PATH:$HOME/gopath/bin 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Bugra Akyildiz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Testing Image](http://img.shields.io/travis/bugra/matrix.svg?style=flat) 2 | ![Issues](http://img.shields.io/github/issues/bugra/matrix.svg?style=flat) 3 | 4 | Matrix 5 | === 6 | matrix is a BSD licensed library that provides common matrix operations written in 7 | Go, inspired by Numpy. It has full coverage for tests. 8 | 9 | ## Documentation 10 | [Godoc](https://godoc.org/github.com/bugra/matrix) 11 | 12 | 13 | ## License 14 | [BSD License](https://github.com/bugra/matrix/blob/master/LICENSE) 15 | 16 | ## Supported Functions 17 | - `where` 18 | - `take` 19 | - `dot product` 20 | - `determinant` 21 | - `minor matrix` 22 | - `cofactor matrix` 23 | - `apply` 24 | - `cumulative sum` 25 | - `lower triangle` 26 | - `upper triangle` 27 | - `diagonal` 28 | -------------------------------------------------------------------------------- /matrix.go: -------------------------------------------------------------------------------- 1 | package matrix 2 | 3 | // http://docs.scipy.org/doc/numpy/reference/generated/numpy.matrix.html 4 | import ( 5 | "math/cmplx" 6 | "sort" 7 | ) 8 | 9 | // Private 10 | // Get a column in the form of a slice from a matrix 11 | func column(matrix [][]float64, columnNumber int) (result []float64) { 12 | result = make([]float64, len(matrix)) 13 | for ii := 0; ii < len(matrix); ii++ { 14 | for jj := 0; jj < len(matrix[0]); jj++ { 15 | result[ii] = matrix[ii][columnNumber] 16 | } 17 | } 18 | return 19 | } 20 | 21 | // Returns the sum of the given two matrix 22 | func Add(firstMatrix [][]float64, secondMatrix [][]float64) (result [][]float64) { 23 | result = make([][]float64, len(firstMatrix)) 24 | for ii := 0; ii < len(firstMatrix); ii++ { 25 | result[ii] = make([]float64, len(firstMatrix[0])) 26 | for jj := 0; jj < len(firstMatrix[0]); jj++ { 27 | result[ii][jj] = firstMatrix[ii][jj] + secondMatrix[ii][jj] 28 | } 29 | } 30 | return 31 | } 32 | 33 | // Subtraction operation on two matrices 34 | func Subtract(firstMatrix [][]float64, secondMatrix [][]float64) [][]float64 { 35 | secondMatrix = MultiplyByScalar(secondMatrix, -1.0) 36 | return Add(firstMatrix, secondMatrix) 37 | } 38 | 39 | // Dot (Inner) product 40 | func DotProduct(firstMatrix [][]float64, secondMatrix [][]float64) (result [][]float64) { 41 | result = make([][]float64, len(firstMatrix)) 42 | for ii := 0; ii < len(firstMatrix); ii++ { 43 | result[ii] = make([]float64, len(secondMatrix[0])) 44 | for jj := 0; jj < len(secondMatrix[0]); jj++ { 45 | for kk := 0; kk < len(secondMatrix); kk++ { 46 | result[ii][jj] += firstMatrix[ii][kk] * secondMatrix[kk][jj] 47 | } 48 | } 49 | } 50 | return 51 | } 52 | 53 | // Calculates the determinant of the matrix 54 | func Determinant(matrix [][]float64) (result float64) { 55 | matrixLength := len(matrix) 56 | sums := make([]float64, matrixLength*2) 57 | for ii := 0; ii < len(sums); ii++ { 58 | sums[ii] = 1 59 | } 60 | 61 | for ii := 0; ii < matrixLength; ii++ { 62 | for jj := 0; jj < matrixLength; jj++ { 63 | if ii-jj < 0 { 64 | sums[matrixLength+ii-jj] *= matrix[ii][jj] 65 | } else { 66 | sums[ii-jj] *= matrix[ii][jj] 67 | } 68 | 69 | if ii+jj >= matrixLength { 70 | sums[ii+jj] *= matrix[ii][jj] 71 | } else { 72 | sums[ii+jj+matrixLength] *= matrix[ii][jj] 73 | } 74 | } 75 | } 76 | 77 | dim := matrixLength * 2 78 | if matrixLength == 2 { 79 | dim = 2 80 | matrixLength = 1 81 | } 82 | 83 | for ii := 0; ii < dim; ii++ { 84 | if ii >= matrixLength { 85 | result -= sums[ii] 86 | } else { 87 | result += sums[ii] 88 | } 89 | } 90 | return 91 | } 92 | 93 | // Minor matrix of a given matrix 94 | func MinorMatrix(matrix [][]float64) (result [][]float64) { 95 | var ( 96 | matrixLength int 97 | ) 98 | 99 | matrixLength = len(matrix) 100 | result = make([][]float64, matrixLength) 101 | for ii := 0; ii < matrixLength; ii++ { 102 | result[ii] = make([]float64, matrixLength) 103 | for jj := 0; jj < matrixLength; jj++ { 104 | auxM := [][]float64{} 105 | for iik := 0; iik < matrixLength; iik++ { 106 | if iik != ii { 107 | auxR := []float64{} 108 | for jjk := 0; jjk < matrixLength; jjk++ { 109 | if jjk != jj { 110 | auxR = append(auxR, matrix[iik][jjk]) 111 | } 112 | } 113 | auxM = append(auxM, auxR) 114 | } 115 | } 116 | result[ii][jj] = Determinant(auxM) 117 | } 118 | } 119 | return 120 | } 121 | 122 | // Returns the Cofactor Matrix 123 | func CofactorMatrix(matrix [][]float64) (result [][]float64) { 124 | result = make([][]float64, len(matrix)) 125 | for ii := 0; ii < len(matrix); ii++ { 126 | result[ii] = make([]float64, len(matrix[0])) 127 | for jj := 0; jj < len(matrix[0]); jj++ { 128 | if (ii+jj)%2 == 0 { 129 | result[ii][jj] = matrix[ii][jj] 130 | } else { 131 | result[ii][jj] = -matrix[ii][jj] 132 | } 133 | } 134 | } 135 | return 136 | } 137 | 138 | // Calculates the inverse matrix 139 | func Inverse(matrix [][]float64) [][]float64 { 140 | determinant := Determinant(matrix) 141 | adj := Transpose(CofactorMatrix(MinorMatrix(matrix))) 142 | return MultiplyByScalar(adj, 1./determinant) 143 | } 144 | 145 | // Divide the first matrix by the second one 146 | func Divide(firstMatrix [][]float64, secondMatrix [][]float64) [][]float64 { 147 | return DotProduct(firstMatrix, Inverse(secondMatrix)) 148 | } 149 | 150 | // Returns the rm of multiply all the elements of a matrix by a float number 151 | func MultiplyByScalar(matrix [][]float64, scalar float64) [][]float64 { 152 | function := func(x float64) float64 { 153 | return x * scalar 154 | } 155 | return Apply(matrix, function) 156 | } 157 | 158 | // Multiply on matrix by the Transposepose of the second matrix 159 | func MultTranspose(firstMatrix [][]float64, secondMatrix [][]float64) (result [][]float64) { 160 | result = make([][]float64, len(firstMatrix)) 161 | for ii := 0; ii < len(firstMatrix); ii++ { 162 | result[ii] = make([]float64, len(secondMatrix)) 163 | for jj := 0; jj < len(secondMatrix); jj++ { 164 | for kk := 0; kk < len(secondMatrix[0]); kk++ { 165 | result[ii][jj] += firstMatrix[ii][kk] * secondMatrix[jj][kk] 166 | } 167 | } 168 | } 169 | return 170 | } 171 | 172 | // Multiplication of two matrices; element-wise 173 | func Multiply(firstMatrix [][]float64, secondMatrix [][]float64) (result [][]float64) { 174 | result = make([][]float64, len(firstMatrix)) 175 | for ii := 0; ii < len(firstMatrix); ii++ { 176 | result[ii] = make([]float64, len(firstMatrix[0])) 177 | for jj := 0; jj < len(firstMatrix[0]); jj++ { 178 | result[ii][jj] = firstMatrix[ii][jj] * secondMatrix[ii][jj] 179 | } 180 | } 181 | return 182 | } 183 | 184 | // Matrix Transpose 185 | func Transpose(matrix [][]float64) (result [][]float64) { 186 | result = make([][]float64, len(matrix[0])) 187 | // Initialize the matrix 188 | for ii := 0; ii < len(matrix[0]); ii++ { 189 | result[ii] = make([]float64, len(matrix)) 190 | for jj := 0; jj < len(matrix); jj++ { 191 | result[ii][jj] = matrix[jj][ii] 192 | } 193 | } 194 | return 195 | } 196 | 197 | // Sum of the matrix along with axis 198 | // axis=0 => row-wise 199 | // axis=1 => column-wise 200 | func Sum(matrix [][]float64, axis int) (result []float64, ok bool) { 201 | rowSum := make([]float64, len(matrix)) 202 | columnSum := make([]float64, len(matrix[0])) 203 | for ii := 0; ii < len(matrix); ii++ { 204 | for jj := 0; jj < len(matrix[0]); jj++ { 205 | rowSum[ii] += matrix[ii][jj] 206 | columnSum[jj] += matrix[ii][jj] 207 | } 208 | } 209 | if axis == 1 { 210 | result = rowSum 211 | ok = true 212 | } else { 213 | result = columnSum 214 | ok = true 215 | } 216 | return 217 | } 218 | 219 | // Maximum of matrix along with axis 220 | // axis=0 => row-wise 221 | // axis=1 => column-wise 222 | func Max(matrix [][]float64, axis int) (result []float64, ok bool) { 223 | var ( 224 | firstDimension int 225 | secondDimension int 226 | ) 227 | firstDimension = len(matrix) 228 | secondDimension = len(matrix[0]) 229 | 230 | rowMax := make([]float64, firstDimension) 231 | columnMax := make([]float64, secondDimension) 232 | deepMatrix := deepCopyMatrix(matrix) 233 | 234 | for ii := 0; ii < firstDimension; ii++ { 235 | sort.Float64s(deepMatrix[ii]) 236 | rowMax[ii] = deepMatrix[ii][secondDimension-1] 237 | 238 | if ii == firstDimension-1 { 239 | for jj := 0; jj < secondDimension; jj++ { 240 | deepCol := deepCopyArray(column(matrix, jj)) 241 | sort.Float64s(deepCol) 242 | columnMax[jj] = deepCol[len(deepCol)-1] 243 | } 244 | } 245 | } 246 | if axis == 1 { 247 | result = rowMax 248 | ok = true 249 | } else { 250 | result = columnMax 251 | ok = true 252 | } 253 | return 254 | } 255 | 256 | // Minimum of matrix along with axis 257 | // axis=0 => row-wise 258 | // axis=1 => column-wise 259 | func Min(matrix [][]float64, axis int) (result []float64, ok bool) { 260 | var ( 261 | firstDimension int 262 | secondDimension int 263 | ) 264 | firstDimension = len(matrix) 265 | secondDimension = len(matrix[0]) 266 | 267 | rowMin := make([]float64, firstDimension) 268 | columnMin := make([]float64, secondDimension) 269 | deepMatrix := deepCopyMatrix(matrix) 270 | 271 | for ii := 0; ii < firstDimension; ii++ { 272 | sort.Float64s(deepMatrix[ii]) 273 | rowMin[ii] = deepMatrix[ii][0] 274 | 275 | if ii == firstDimension-1 { 276 | for jj := 0; jj < secondDimension; jj++ { 277 | deepCol := deepCopyArray(column(matrix, jj)) 278 | sort.Float64s(deepCol) 279 | columnMin[jj] = deepCol[0] 280 | } 281 | } 282 | } 283 | if axis == 1 { 284 | result = rowMin 285 | ok = true 286 | } else { 287 | result = columnMin 288 | ok = true 289 | } 290 | return 291 | } 292 | 293 | // Median of matrix along with axis 294 | // axis=0 => row-wise 295 | // axis=1 => column-wise 296 | func Median(matrix [][]float64, axis int) (result []float64, ok bool) { 297 | var ( 298 | firstDimension int 299 | secondDimension int 300 | halfRow int 301 | halfCol int 302 | isFirstDivisibleBy2 bool 303 | isSecondDivisibleBy2 bool 304 | ) 305 | firstDimension = len(matrix) 306 | secondDimension = len(matrix[0]) 307 | 308 | if firstDimension%2 == 0 { 309 | halfRow = firstDimension / 2 310 | isFirstDivisibleBy2 = true 311 | } else { 312 | halfRow = (firstDimension - 1) / 2 313 | } 314 | 315 | if secondDimension%2 == 0 { 316 | halfCol = secondDimension / 2 317 | isSecondDivisibleBy2 = true 318 | } else { 319 | halfCol = (secondDimension - 1) / 2 320 | } 321 | rowMedian := make([]float64, firstDimension) 322 | columnMedian := make([]float64, secondDimension) 323 | 324 | deepMatrix := deepCopyMatrix(matrix) 325 | 326 | for ii := 0; ii < firstDimension; ii++ { 327 | sort.Float64s(deepMatrix[ii]) 328 | if isSecondDivisibleBy2 && secondDimension > halfRow+1 { 329 | rowMedian[ii] = (deepMatrix[ii][halfRow] + deepMatrix[ii][halfRow+1]) / 2. 330 | } else if secondDimension == 2 { 331 | rowMedian[ii] = (deepMatrix[ii][0] + deepMatrix[ii][1]) / 2. 332 | } else { 333 | rowMedian[ii] = deepMatrix[ii][halfRow] 334 | } 335 | 336 | if ii == firstDimension-1 { 337 | for jj := 0; jj < secondDimension; jj++ { 338 | deepCol := deepCopyArray(column(matrix, jj)) 339 | sort.Float64s(deepCol) 340 | if isFirstDivisibleBy2 && len(deepCol) > halfCol+1 { 341 | columnMedian[jj] = (deepCol[halfCol] + deepCol[halfCol+1]) / 2. 342 | } else if len(deepCol) == 2 { 343 | columnMedian[jj] = (deepCol[0] + deepCol[1]) / 2. 344 | } else { 345 | columnMedian[jj] = deepCol[halfCol] 346 | } 347 | 348 | } 349 | } 350 | } 351 | 352 | if axis == 1 { 353 | result = rowMedian 354 | ok = true 355 | } else { 356 | result = columnMedian 357 | ok = true 358 | } 359 | return 360 | } 361 | 362 | // Mean of matrix along with axis 363 | // axis=0 => row-wise 364 | // axis=1 => column-wise 365 | func Mean(matrix [][]float64, axis int) (result []float64, ok bool) { 366 | var dim int 367 | sum, ok := Sum(matrix, axis) 368 | if !ok { 369 | return 370 | } 371 | result = make([]float64, len(sum)) 372 | if axis == 0 { 373 | dim = len(matrix) 374 | } else { 375 | dim = len(matrix[0]) 376 | } 377 | for ii, value := range sum { 378 | result[ii] = value / float64(dim) 379 | } 380 | return 381 | } 382 | 383 | // Cumulative Sum of Matrix along with axis 384 | // axis=0 => row-wise 385 | // axis=1 => column-wise 386 | func CumulativeSum(matrix [][]float64, axis int) (result []float64, ok bool) { 387 | result, ok = Sum(matrix, axis) 388 | temp := 0. 389 | for ii, jj := range result { 390 | temp += jj 391 | result[ii] = temp 392 | } 393 | return 394 | } 395 | 396 | // Sum all the elements in a matrix 397 | func SumAll(m [][]float64) (result float64) { 398 | for ii := 0; ii < len(m); ii++ { 399 | for jj := 0; jj < len(m[0]); jj++ { 400 | result += m[ii][jj] 401 | } 402 | } 403 | return 404 | } 405 | 406 | // Apply a function to all the elements of a matrix, 407 | //the function will receive a float64 as param and returns a float64 408 | func Apply(matrix [][]float64, function func(x float64) float64) (result [][]float64) { 409 | result = make([][]float64, len(matrix)) 410 | for ii := 0; ii < len(matrix); ii++ { 411 | result[ii] = make([]float64, len(matrix[0])) 412 | for jj := 0; jj < len(matrix[0]); jj++ { 413 | result[ii][jj] = function(matrix[ii][jj]) 414 | } 415 | } 416 | return 417 | } 418 | 419 | // Apply a function to a complex matrix 420 | // the function will receive a complex128 and returns a complex128 421 | func ComplexApply(matrix [][]complex128, function func(x complex128) complex128) (result [][]complex128) { 422 | result = make([][]complex128, len(matrix)) 423 | for ii := 0; ii < len(matrix); ii++ { 424 | result[ii] = make([]complex128, len(matrix[0])) 425 | for jj := 0; jj < len(matrix[0]); jj++ { 426 | result[ii][jj] = function(matrix[ii][jj]) 427 | } 428 | } 429 | return 430 | } 431 | 432 | // Deep Copy of an Array 433 | func deepCopyMatrix(matrix [][]float64) (deepCopy [][]float64) { 434 | deepCopy = make([][]float64, len(matrix)) 435 | for ii := 0; ii < len(matrix); ii++ { 436 | deepCopy[ii] = make([]float64, len(matrix[ii])) 437 | for jj := 0; jj < len(matrix[ii]); jj++ { 438 | deepCopy[ii][jj] = matrix[ii][jj] 439 | } 440 | } 441 | return 442 | } 443 | 444 | func deepCopyArray(array []float64) (deepCopy []float64) { 445 | deepCopy = make([]float64, len(array)) 446 | for ii := 0; ii < len(array); ii++ { 447 | deepCopy[ii] = array[ii] 448 | } 449 | return 450 | } 451 | 452 | // Concatenate two matrices along with their axises 453 | // axis=0 => row-wise 454 | // axis=1 => column-wise 455 | func Concatenate(firstMatrix [][]float64, secondMatrix [][]float64, axis int) (result [][]float64) { 456 | if axis == 0 { 457 | result = make([][]float64, len(firstMatrix)+len(secondMatrix)) 458 | for ii := 0; ii < len(firstMatrix)+len(secondMatrix); ii++ { 459 | if ii < len(firstMatrix) { 460 | result[ii] = firstMatrix[ii] 461 | } else { 462 | result[ii] = secondMatrix[ii-len(firstMatrix)] 463 | } 464 | } 465 | } else { 466 | result = make([][]float64, len(firstMatrix)) 467 | for i := 0; i < len(firstMatrix); i++ { 468 | result[i] = make([]float64, len(firstMatrix[i])+len(secondMatrix[i])) 469 | for j := 0; j < len(firstMatrix[i]); j++ { 470 | result[i][j] = firstMatrix[i][j] 471 | } 472 | for j := 0; j < len(secondMatrix[i]); j++ { 473 | result[i][j+len(firstMatrix[i])] = secondMatrix[i][j] 474 | } 475 | } 476 | } 477 | return 478 | } 479 | 480 | // Returns an array where diagonal elements are 1 and remaining 481 | // positions are 0 482 | // If it has been passed one parameter, it yields a square matrix 483 | // Two parameters define the size of the matrix 484 | func Eye(args ...int) (result [][]float64, ok bool) { 485 | result, ok = Zeros(args) 486 | if ok { 487 | for ii := 0; ii < len(result); ii++ { 488 | for jj := 0; jj < len(result[0]); jj++ { 489 | if ii == jj { 490 | result[ii][jj] = 1. 491 | } 492 | } 493 | } 494 | } 495 | return 496 | } 497 | 498 | // Returns an array filled with 0.s 499 | // If it has been passed one parameter, it yields a square matrix 500 | // Two parameters define the size of the matrix 501 | func Zeros(args []int) (result [][]float64, ok bool) { 502 | dims := make([]int, 2) 503 | var isValid bool 504 | if len(args) == 1 { 505 | dims[0] = args[0] 506 | dims[1] = args[0] 507 | isValid = true 508 | } else if len(args) == 2 { 509 | dims[0] = args[0] 510 | dims[1] = args[1] 511 | isValid = true 512 | } 513 | if isValid { 514 | result = make([][]float64, dims[0]) 515 | for ii := 0; ii < dims[0]; ii++ { 516 | result[ii] = make([]float64, dims[1]) 517 | } 518 | ok = true 519 | } 520 | return 521 | } 522 | 523 | // Returns the diagonal of a matrix 524 | func Diagonal(matrix [][]float64) (result []float64, ok bool) { 525 | var ( 526 | minDimension int 527 | ii int 528 | jj int 529 | ) 530 | firstDimension, secondDimension := len(matrix), len(matrix[0]) 531 | if firstDimension < secondDimension { 532 | minDimension = firstDimension 533 | } else { 534 | minDimension = secondDimension 535 | } 536 | for ii = 0; ii < minDimension; ii++ { 537 | for jj = 0; jj < minDimension; jj++ { 538 | if ii == jj { 539 | result = append(result, matrix[ii][jj]) 540 | } 541 | } 542 | ok = true 543 | } 544 | return 545 | } 546 | 547 | // Lower Triangle Matrix 548 | func LowerTriangle(matrix [][]float64) (result [][]float64) { 549 | result = make([][]float64, len(matrix)) 550 | for ii := 0; ii < len(matrix); ii++ { 551 | result[ii] = make([]float64, len(matrix[ii])) 552 | for jj := 0; jj < len(matrix[0]); jj++ { 553 | if ii >= jj { 554 | result[ii][jj] = matrix[ii][jj] 555 | } 556 | 557 | } 558 | } 559 | return 560 | } 561 | 562 | // Upper Triangle of Matrix 563 | func UpperTriangle(matrix [][]float64) (result [][]float64) { 564 | firstDimension, secondDimension := len(matrix), len(matrix[0]) 565 | result = make([][]float64, firstDimension) 566 | for ii := 0; ii < firstDimension; ii++ { 567 | result[ii] = make([]float64, secondDimension) 568 | for jj := 0; jj < secondDimension; jj++ { 569 | if ii <= jj { 570 | result[ii][jj] = matrix[ii][jj] 571 | } 572 | } 573 | } 574 | return 575 | } 576 | 577 | // Take the elements of the matrix given in indices 578 | // uses so called fancy indexing to determine the positions of the 579 | // array 580 | func Take(matrix [][]float64, indices []int) (result []float64, ok bool) { 581 | var ( 582 | first int 583 | second int 584 | ) 585 | firstDimension, secondDimension := len(matrix), len(matrix[0]) 586 | sort.Ints(indices) 587 | if indices[len(indices)-1] < firstDimension*secondDimension { 588 | ok = true 589 | } 590 | if ok { 591 | for ii := 0; ii < len(indices); ii++ { 592 | first, second = indices[ii]/secondDimension, indices[ii]%secondDimension 593 | result = append(result, matrix[first][second]) 594 | } 595 | } 596 | 597 | return 598 | } 599 | 600 | // Returns the elements of the matrix which returns true for a given function 601 | func Where(matrix [][]float64, function func(x float64) bool) (result []float64) { 602 | for ii := 0; ii < len(matrix); ii++ { 603 | for jj := 0; jj < len(matrix[0]); jj++ { 604 | if function(matrix[ii][jj]) { 605 | result = append(result, matrix[ii][jj]) 606 | } 607 | } 608 | } 609 | return 610 | } 611 | 612 | // Returns the Congugate Matrix 613 | func ConjugateMatrix(matrix [][]complex128) (result [][]complex128) { 614 | function := func(number complex128) (result complex128) { 615 | return cmplx.Conj(number) 616 | } 617 | result = ComplexApply(matrix, function) 618 | return 619 | } 620 | -------------------------------------------------------------------------------- /matrix_test.go: -------------------------------------------------------------------------------- 1 | package matrix 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | const SMALL_FLOAT float64 = 0.0000001 8 | 9 | // TODO: Var, std, correlate, corrcoef, covariance 10 | // http://docs.scipy.org/doc/numpy/reference/generated/numpy.cov.html 11 | 12 | func TestDotProduct(t *testing.T) { 13 | // 2x3 14 | firstMatrix := [][]float64{ 15 | []float64{1, 2, 3}, 16 | []float64{4, 5, 6}, 17 | } 18 | 19 | // 3x2 20 | secondMatrix := [][]float64{ 21 | []float64{1, 7}, 22 | []float64{2, 8}, 23 | []float64{3, 9}, 24 | } 25 | 26 | // 2x2 27 | actual := [][]float64{ 28 | []float64{14, 50}, 29 | []float64{32, 122}, 30 | } 31 | 32 | computed := DotProduct(firstMatrix, secondMatrix) 33 | 34 | for i := 0; i < len(computed); i++ { 35 | for j := 0; j < len(computed[i]); j++ { 36 | if computed[i][j] != actual[i][j] { 37 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 38 | } 39 | } 40 | } 41 | } 42 | 43 | func TestMultiplyByScalar(t *testing.T) { 44 | // 2x3 45 | firstMatrix := [][]float64{ 46 | []float64{1, 2, 3}, 47 | []float64{4, 5, 6}, 48 | } 49 | 50 | actual := [][]float64{ 51 | []float64{-1, -2, -3}, 52 | []float64{-4, -5, -6}, 53 | } 54 | 55 | computed := MultiplyByScalar(firstMatrix, -1) 56 | for ii := 0; ii < len(firstMatrix); ii++ { 57 | for jj := 0; jj < len(firstMatrix[ii]); jj++ { 58 | if actual[ii][jj] != computed[ii][jj] { 59 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 60 | } 61 | } 62 | } 63 | } 64 | 65 | func TestAdd(t *testing.T) { 66 | firstMatrix := [][]float64{ 67 | []float64{3, 2, 1}, 68 | []float64{9, 5, 7}, 69 | } 70 | secondMatrix := [][]float64{ 71 | []float64{2, 3, 4}, 72 | []float64{1, 4, 7}, 73 | } 74 | 75 | actual := [][]float64{ 76 | []float64{5, 5, 5}, 77 | []float64{10, 9, 14}, 78 | } 79 | 80 | computed := Add(firstMatrix, secondMatrix) 81 | 82 | for ii := 0; ii < len(computed); ii++ { 83 | for jj := 0; jj < len(computed); jj++ { 84 | if computed[ii][jj] != actual[ii][jj] { 85 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 86 | } 87 | } 88 | } 89 | } 90 | 91 | func TestMultTrans(t *testing.T) { 92 | firstMatrix := [][]float64{ 93 | []float64{3, 2, 1}, 94 | []float64{9, 5, 7}, 95 | } 96 | secondMatrix := [][]float64{ 97 | []float64{2, 3, 4}, 98 | []float64{1, 4, 7}, 99 | } 100 | 101 | actual := DotProduct(firstMatrix, Transpose(secondMatrix)) 102 | computed := MultTranspose(firstMatrix, secondMatrix) 103 | 104 | for i := 0; i < len(computed); i++ { 105 | for j := 0; j < len(computed); j++ { 106 | if computed[i][j] != actual[i][j] { 107 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 108 | } 109 | } 110 | } 111 | } 112 | 113 | func TestMultiply(t *testing.T) { 114 | firstMatrix := [][]float64{ 115 | []float64{1, 2, 3}, 116 | []float64{4, 5, 6}, 117 | } 118 | secondMatrix := [][]float64{ 119 | []float64{4, 5, 6}, 120 | []float64{7, 8, 9}, 121 | } 122 | 123 | actual := [][]float64{ 124 | []float64{4, 10, 18}, 125 | []float64{28, 40, 54}, 126 | } 127 | 128 | computed := Multiply(firstMatrix, secondMatrix) 129 | 130 | for i := 0; i < len(computed); i++ { 131 | for j := 0; j < len(computed); j++ { 132 | if computed[i][j] != actual[i][j] { 133 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 134 | } 135 | } 136 | } 137 | } 138 | 139 | func TestSubtract(t *testing.T) { 140 | firstMatrix := [][]float64{ 141 | []float64{1, 2, 3}, 142 | []float64{7, 8, 9}, 143 | } 144 | secondMatrix := [][]float64{ 145 | []float64{4, 5, 6}, 146 | []float64{4, 5, 6}, 147 | } 148 | 149 | actual := [][]float64{ 150 | []float64{-3, -3, -3}, 151 | []float64{3, 3, 3}, 152 | } 153 | 154 | computed := Subtract(firstMatrix, secondMatrix) 155 | 156 | for ii := 0; ii < len(computed); ii++ { 157 | for jj := 0; jj < len(computed); jj++ { 158 | if computed[ii][jj] != actual[ii][jj] { 159 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 160 | } 161 | } 162 | } 163 | } 164 | 165 | func TestMatrixTrans(t *testing.T) { 166 | firstMatrix := [][]float64{ 167 | []float64{3, 2, 1}, 168 | []float64{9, 5, 7}, 169 | } 170 | 171 | actual := [][]float64{ 172 | []float64{3, 9}, 173 | []float64{2, 5}, 174 | []float64{1, 7}, 175 | } 176 | 177 | computed := Transpose(firstMatrix) 178 | 179 | for i := 0; i < len(computed); i++ { 180 | for j := 0; j < len(computed[0]); j++ { 181 | if computed[i][j] != actual[i][j] { 182 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 183 | } 184 | } 185 | } 186 | } 187 | 188 | func TestSum(t *testing.T) { 189 | matrix := [][]float64{ 190 | []float64{0, 1}, 191 | []float64{0, 5}, 192 | } 193 | rowSum, ok := Sum(matrix, 0) 194 | actual := []float64{0, 6} 195 | if !ok { 196 | t.Errorf("%b", ok) 197 | } 198 | for ii := 0; ii < len(rowSum); ii++ { 199 | if rowSum[ii] != actual[ii] { 200 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], rowSum[ii]) 201 | } 202 | } 203 | 204 | colSum, ok := Sum(matrix, 1) 205 | if !ok { 206 | t.Errorf("%b", ok) 207 | } 208 | actual = []float64{1, 5} 209 | for ii := 0; ii < len(colSum); ii++ { 210 | if colSum[ii] != actual[ii] { 211 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], colSum[ii]) 212 | } 213 | } 214 | } 215 | 216 | func TestMean(t *testing.T) { 217 | matrix := [][]float64{ 218 | []float64{1, 2}, 219 | []float64{3, 4}, 220 | } 221 | computed, ok := Mean(matrix, 0) 222 | if !ok { 223 | t.Errorf("%b", ok) 224 | } 225 | actual := []float64{2, 3} 226 | for ii, _ := range computed { 227 | if computed[ii] != actual[ii] { 228 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 229 | } 230 | } 231 | computed, ok = Mean(matrix, 1) 232 | if !ok { 233 | t.Errorf("%b", ok) 234 | } 235 | actual = []float64{1.5, 3.5} 236 | for ii, _ := range computed { 237 | if computed[ii] != actual[ii] { 238 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 239 | } 240 | } 241 | } 242 | 243 | func TestMedian(t *testing.T) { 244 | matrix := [][]float64{ 245 | []float64{10, 7, 4}, 246 | []float64{3, 2, 1}, 247 | } 248 | 249 | actual := []float64{6.5, 4.5, 2.5} 250 | computed, ok := Median(matrix, 0) 251 | if !ok { 252 | t.Errorf("%b", ok) 253 | } 254 | 255 | for ii, _ := range computed { 256 | if computed[ii] != actual[ii] { 257 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 258 | } 259 | } 260 | actual = []float64{7, 2} 261 | computed, ok = Median(matrix, 1) 262 | 263 | if !ok { 264 | t.Errorf("%b", ok) 265 | } 266 | 267 | for ii, _ := range computed { 268 | if computed[ii] != actual[ii] { 269 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 270 | } 271 | } 272 | } 273 | 274 | func TestMax(t *testing.T) { 275 | matrix := [][]float64{ 276 | []float64{2, 3, 4}, 277 | []float64{1, 5, 2}, 278 | } 279 | 280 | actual := []float64{2, 5, 4} 281 | computed, ok := Max(matrix, 0) 282 | 283 | if !ok { 284 | t.Errorf("%b", ok) 285 | } 286 | 287 | for ii, _ := range computed { 288 | if computed[ii] != actual[ii] { 289 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 290 | } 291 | } 292 | 293 | actual = []float64{4, 5} 294 | computed, ok = Max(matrix, 1) 295 | 296 | if !ok { 297 | t.Errorf("%b", ok) 298 | } 299 | 300 | for ii, _ := range computed { 301 | if computed[ii] != actual[ii] { 302 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 303 | } 304 | } 305 | 306 | } 307 | 308 | func TestMin(t *testing.T) { 309 | matrix := [][]float64{ 310 | []float64{2, 3, 4}, 311 | []float64{1, 5, 2}, 312 | } 313 | 314 | actual := []float64{1, 3, 2} 315 | computed, ok := Min(matrix, 0) 316 | 317 | if !ok { 318 | t.Errorf("%b", ok) 319 | } 320 | for ii, _ := range computed { 321 | if computed[ii] != actual[ii] { 322 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 323 | } 324 | } 325 | 326 | actual = []float64{2, 1} 327 | computed, ok = Min(matrix, 1) 328 | 329 | if !ok { 330 | t.Errorf("%b", ok) 331 | } 332 | 333 | for ii, _ := range computed { 334 | if computed[ii] != actual[ii] { 335 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 336 | } 337 | } 338 | 339 | } 340 | 341 | func TestSumAll(t *testing.T) { 342 | m := [][]float64{ 343 | []float64{1, 2, 3}, 344 | []float64{4, 5, 6}, 345 | } 346 | 347 | actual := 21. 348 | computed := SumAll(m) 349 | 350 | if computed != actual { 351 | t.Errorf("Actual value: %f, computed value: %f", actual, computed) 352 | } 353 | } 354 | 355 | func TestCumulativeSum(t *testing.T) { 356 | matrix := [][]float64{ 357 | []float64{2, 1}, 358 | []float64{2, 5}, 359 | } 360 | 361 | computed, ok := CumulativeSum(matrix, 0) 362 | actual := []float64{4, 10} 363 | if !ok { 364 | t.Errorf("%b", ok) 365 | } 366 | for ii := 0; ii < len(computed); ii++ { 367 | if computed[ii] != actual[ii] { 368 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 369 | } 370 | } 371 | computed, ok = CumulativeSum(matrix, 1) 372 | actual = []float64{3, 10} 373 | if !ok { 374 | t.Errorf("%b", ok) 375 | } 376 | for ii := 0; ii < len(computed); ii++ { 377 | if computed[ii] != actual[ii] { 378 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 379 | } 380 | } 381 | } 382 | 383 | func TestApply(t *testing.T) { 384 | m := [][]float64{ 385 | []float64{4, 2, 1}, 386 | []float64{8, 3, 6}, 387 | } 388 | 389 | actual := [][]float64{ 390 | []float64{2, 1, 0.5}, 391 | []float64{4, 1.5, 3}, 392 | } 393 | 394 | function := func(x float64) float64 { 395 | return x / 2 396 | } 397 | 398 | computed := Apply(m, function) 399 | 400 | for ii := 0; ii < len(computed); ii++ { 401 | for jj := 0; jj < len(computed[0]); jj++ { 402 | if computed[ii][jj] != actual[ii][jj] { 403 | t.Error("Expected computed on pos:", ii, jj, ":", actual[ii][jj], "but obtained:", computed[ii][jj]) 404 | } 405 | } 406 | } 407 | } 408 | 409 | func TestWhere(t *testing.T) { 410 | m := [][]float64{ 411 | []float64{4, 2, 1}, 412 | []float64{8, 3, 6}, 413 | } 414 | actual := []float64{4, 8, 6} 415 | function := func(x float64) bool { 416 | return x > 3 417 | } 418 | 419 | computed := Where(m, function) 420 | for ii := 0; ii < len(computed); ii++ { 421 | if computed[ii] != actual[ii] { 422 | t.Error("Expected computed on pos:", ii, ":", actual[ii], "but obtained:", computed[ii]) 423 | } 424 | } 425 | } 426 | 427 | func TestDeterminant(t *testing.T) { 428 | matrix := [][]float64{ 429 | []float64{-2, 2, -3}, 430 | []float64{-1, 1, 3}, 431 | []float64{2, 0, -1}, 432 | } 433 | 434 | determinant := Determinant(matrix) 435 | actual := 18. 436 | if determinant != actual { 437 | t.Errorf("Computed Determinant: %f\nActual Determinant: %f", determinant, actual) 438 | } 439 | 440 | matrix = [][]float64{ 441 | []float64{1, 3}, 442 | []float64{4, 2}, 443 | } 444 | 445 | determinant = Determinant(matrix) 446 | actual = -10. 447 | 448 | if determinant != actual { 449 | t.Errorf("Computed Determinant: %f\nActual Determinant: %f", determinant, actual) 450 | } 451 | 452 | matrix = [][]float64{ 453 | []float64{1, 2, 3}, 454 | []float64{2, 4, 6}, 455 | []float64{5, 8, 12}, 456 | } 457 | actual = 0. 458 | determinant = Determinant(matrix) 459 | if determinant != actual { 460 | t.Errorf("Computed Determinant: %f\nActual Determinant: %f", determinant, actual) 461 | } 462 | } 463 | 464 | func TestMinorMatrix(t *testing.T) { 465 | m := [][]float64{ 466 | []float64{1, 3, 1}, 467 | []float64{1, 1, 2}, 468 | []float64{2, 3, 4}, 469 | } 470 | 471 | actual := [][]float64{ 472 | []float64{-2, 0, 1}, 473 | []float64{9, 2, -3}, 474 | []float64{5, 1, -2}, 475 | } 476 | 477 | computed := MinorMatrix(m) 478 | 479 | for i := 0; i < len(computed); i++ { 480 | for j := 0; j < len(computed[0]); j++ { 481 | if computed[i][j] != actual[i][j] { 482 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 483 | } 484 | } 485 | } 486 | } 487 | 488 | func TestCofactorMatrix(t *testing.T) { 489 | m := [][]float64{ 490 | []float64{1, 3, 1}, 491 | []float64{1, -1, -2}, 492 | []float64{2, 3, 4}, 493 | } 494 | 495 | actual := [][]float64{ 496 | []float64{1, -3, 1}, 497 | []float64{-1, -1, 2}, 498 | []float64{2, -3, 4}, 499 | } 500 | 501 | computed := CofactorMatrix(m) 502 | 503 | for i := 0; i < len(computed); i++ { 504 | for j := 0; j < len(computed[0]); j++ { 505 | if computed[i][j] != actual[i][j] { 506 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 507 | } 508 | } 509 | } 510 | } 511 | 512 | func TestInverse(t *testing.T) { 513 | m := [][]float64{ 514 | []float64{1, 3, 1}, 515 | []float64{1, 1, 2}, 516 | []float64{2, 3, 4}, 517 | } 518 | 519 | actual := [][]float64{ 520 | []float64{2, 9, -5}, 521 | []float64{0, -2, 1}, 522 | []float64{-1, -3, 2}, 523 | } 524 | 525 | computed := Inverse(m) 526 | 527 | for i := 0; i < len(computed); i++ { 528 | for j := 0; j < len(computed[0]); j++ { 529 | if computed[i][j] != actual[i][j] { 530 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 531 | } 532 | } 533 | } 534 | } 535 | 536 | func TestColumn(t *testing.T) { 537 | matrix := [][]float64{ 538 | []float64{1, 2, 3}, 539 | []float64{3, 2, 1}, 540 | []float64{2, 1, 3}, 541 | } 542 | 543 | computed := column(matrix, 0) 544 | 545 | actual := []float64{1, 3, 2} 546 | 547 | for ii := 0; ii < len(computed); ii++ { 548 | if computed[ii] != actual[ii] { 549 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 550 | } 551 | } 552 | 553 | computed = column(matrix, 1) 554 | 555 | actual = []float64{2, 2, 1} 556 | 557 | for ii := 0; ii < len(computed); ii++ { 558 | if computed[ii] != actual[ii] { 559 | t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 560 | } 561 | } 562 | 563 | computed = column(matrix, 2) 564 | 565 | actual = []float64{3, 1, 3} 566 | 567 | for ii := 0; ii < len(computed); ii++ { 568 | if computed[ii] != actual[ii] { 569 | //t.Errorf("Actual value: %f, computed value: %f", actual[ii], computed[ii]) 570 | } 571 | } 572 | } 573 | 574 | func TestDiv(t *testing.T) { 575 | firstMatrix := [][]float64{ 576 | []float64{1, 2, 3}, 577 | []float64{3, 2, 1}, 578 | []float64{2, 1, 3}, 579 | } 580 | 581 | secondMatrix := [][]float64{ 582 | []float64{4, 5, 6}, 583 | []float64{6, 5, 4}, 584 | []float64{4, 6, 5}, 585 | } 586 | 587 | actual := [][]float64{ 588 | []float64{7.0 / 10.0, 3.0 / 10.0, 0}, 589 | []float64{-3.0 / 10.0, 7.0 / 10.0, 0}, 590 | []float64{6.0 / 5.0, 1.0 / 5.0, -1}, 591 | } 592 | 593 | computed := Divide(firstMatrix, secondMatrix) 594 | 595 | for i := 0; i < len(computed); i++ { 596 | for j := 0; j < len(computed); j++ { 597 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 598 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 599 | } 600 | } 601 | } 602 | } 603 | 604 | func TestDiagonal(t *testing.T) { 605 | matrix := [][]float64{ 606 | []float64{0, 1, 2}, 607 | []float64{3, 4, 5}, 608 | []float64{6, 7, 8}, 609 | } 610 | computed, ok := Diagonal(matrix) 611 | actual := []float64{0, 4, 8} 612 | if !ok { 613 | t.Errorf("%b", ok) 614 | } 615 | for ii := 0; ii < len(computed); ii++ { 616 | if computed[ii] != actual[ii] { 617 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d]", actual[ii], computed[ii], ii) 618 | } 619 | } 620 | matrix = [][]float64{ 621 | []float64{1, 4, 7}, 622 | []float64{2, 4, 8}, 623 | } 624 | actual = []float64{1, 4} 625 | computed, ok = Diagonal(matrix) 626 | if !ok { 627 | t.Errorf("%b", ok) 628 | } 629 | for ii := 0; ii < len(computed); ii++ { 630 | if computed[ii] != actual[ii] { 631 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d]", actual[ii], computed[ii], ii) 632 | } 633 | } 634 | matrix = [][]float64{ 635 | []float64{1, 2}, 636 | []float64{4, 4}, 637 | []float64{7, 8}, 638 | } 639 | computed, ok = Diagonal(matrix) 640 | if !ok { 641 | t.Errorf("%b", ok) 642 | } 643 | for ii := 0; ii < len(computed); ii++ { 644 | if computed[ii] != actual[ii] { 645 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d]", actual[ii], computed[ii], ii) 646 | } 647 | } 648 | matrix = [][]float64{ 649 | []float64{7}, 650 | } 651 | actual = []float64{7} 652 | computed, ok = Diagonal(matrix) 653 | if !ok { 654 | t.Errorf("%b", ok) 655 | } 656 | for ii := 0; ii < len(computed); ii++ { 657 | if computed[ii] != actual[ii] { 658 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d]", actual[ii], computed[ii], ii) 659 | } 660 | } 661 | } 662 | 663 | func TestZeros(t *testing.T) { 664 | dims := []int{3} 665 | computed, ok := Zeros(dims) 666 | actual := [][]float64{ 667 | []float64{0, 0, 0}, 668 | []float64{0, 0, 0}, 669 | []float64{0, 0, 0}, 670 | } 671 | if !ok { 672 | t.Errorf("%b", ok) 673 | } 674 | for i := 0; i < len(computed); i++ { 675 | for j := 0; j < len(computed); j++ { 676 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 677 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 678 | } 679 | } 680 | } 681 | dims = []int{2, 4} 682 | computed, ok = Zeros(dims) 683 | actual = [][]float64{ 684 | []float64{0, 0, 0, 0}, 685 | []float64{0, 0, 0, 0}, 686 | } 687 | if !ok { 688 | t.Errorf("%b", ok) 689 | } 690 | for i := 0; i < len(computed); i++ { 691 | for j := 0; j < len(computed); j++ { 692 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 693 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 694 | } 695 | } 696 | } 697 | 698 | } 699 | 700 | func TestEye(t *testing.T) { 701 | computed, ok := Eye(3) 702 | actual := [][]float64{ 703 | []float64{1, 0, 0}, 704 | []float64{0, 1, 0}, 705 | []float64{0, 0, 1}, 706 | } 707 | if !ok { 708 | t.Errorf("%b", ok) 709 | } 710 | for i := 0; i < len(computed); i++ { 711 | for j := 0; j < len(computed); j++ { 712 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 713 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 714 | } 715 | } 716 | } 717 | computed, ok = Eye(2, 4) 718 | actual = [][]float64{ 719 | []float64{1, 0, 0, 0}, 720 | []float64{0, 1, 0, 0}, 721 | } 722 | if !ok { 723 | t.Errorf("%b", ok) 724 | } 725 | for i := 0; i < len(computed); i++ { 726 | for j := 0; j < len(computed); j++ { 727 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 728 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 729 | } 730 | } 731 | } 732 | 733 | } 734 | 735 | func TestConcatenate(t *testing.T) { 736 | firstMatrix := [][]float64{ 737 | []float64{1, 2, 3}, 738 | []float64{4, 5, 6}, 739 | []float64{7, 8, 9}, 740 | } 741 | 742 | secondMatrix := [][]float64{ 743 | []float64{4, 5}, 744 | []float64{7, 8}, 745 | []float64{10, 11}, 746 | } 747 | 748 | thirdMatrix := [][]float64{ 749 | []float64{10, 11, 12}, 750 | []float64{13, 14, 15}, 751 | []float64{16, 17, 18}, 752 | } 753 | 754 | actual := [][]float64{ 755 | []float64{1, 2, 3, 4, 5}, 756 | []float64{4, 5, 6, 7, 8}, 757 | []float64{7, 8, 9, 10, 11}, 758 | } 759 | 760 | computed := Concatenate(firstMatrix, secondMatrix, 1) 761 | 762 | for i := 0; i < len(computed); i++ { 763 | for j := 0; j < len(computed); j++ { 764 | if computed[i][j]-actual[i][j] > SMALL_FLOAT { 765 | t.Error("Expected computed on pos:", i, j, ":", actual[i][j], "but obtained:", computed[i][j]) 766 | } 767 | } 768 | } 769 | 770 | computed = Concatenate(firstMatrix, thirdMatrix, 0) 771 | actual = [][]float64{ 772 | []float64{1, 2, 3}, 773 | []float64{4, 5, 6}, 774 | []float64{7, 8, 9}, 775 | []float64{10, 11, 12}, 776 | []float64{13, 14, 15}, 777 | []float64{16, 17, 18}, 778 | } 779 | for ii := 0; ii < len(computed); ii++ { 780 | for jj := 0; jj < len(computed[ii]); jj++ { 781 | if computed[ii][jj] != actual[ii][jj] { 782 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 783 | } 784 | } 785 | } 786 | } 787 | 788 | func TestLowerTriangle(t *testing.T) { 789 | matrix := [][]float64{ 790 | []float64{1, 2, 3}, 791 | []float64{4, 5, 6}, 792 | []float64{7, 8, 9}, 793 | []float64{10, 11, 12}, 794 | } 795 | computed := LowerTriangle(matrix) 796 | actual := [][]float64{ 797 | []float64{1, 0, 0}, 798 | []float64{4, 5, 0}, 799 | []float64{7, 8, 9}, 800 | []float64{10, 11, 12}, 801 | } 802 | for ii := 0; ii < len(computed); ii++ { 803 | for jj := 0; jj < len(computed[ii]); jj++ { 804 | if computed[ii][jj] != actual[ii][jj] { 805 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 806 | } 807 | } 808 | } 809 | } 810 | 811 | func TestUpperTriangle(t *testing.T) { 812 | matrix := [][]float64{ 813 | []float64{1, 2, 3}, 814 | []float64{4, 5, 6}, 815 | []float64{7, 8, 9}, 816 | []float64{10, 11, 12}, 817 | } 818 | computed := UpperTriangle(matrix) 819 | actual := [][]float64{ 820 | []float64{1, 2, 3}, 821 | []float64{0, 5, 6}, 822 | []float64{0, 0, 9}, 823 | []float64{0, 0, 0}, 824 | } 825 | for ii := 0; ii < len(computed); ii++ { 826 | for jj := 0; jj < len(computed[ii]); jj++ { 827 | if computed[ii][jj] != actual[ii][jj] { 828 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 829 | } 830 | } 831 | } 832 | } 833 | 834 | func TestTake(t *testing.T) { 835 | matrix := [][]float64{ 836 | []float64{4, 3}, 837 | []float64{5, 7}, 838 | []float64{6, 8}, 839 | } 840 | indices := []int{0, 1, 4} 841 | computed, ok := Take(matrix, indices) 842 | actual := []float64{4, 3, 6} 843 | if !ok { 844 | t.Errorf("%b", ok) 845 | } 846 | for ii := 0; ii < len(computed); ii++ { 847 | if computed[ii] != actual[ii] { 848 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d]", actual[ii], computed[ii], ii) 849 | } 850 | } 851 | } 852 | 853 | func TestConjugateMatrix(t *testing.T) { 854 | complexMatrix := [][]complex128{ 855 | []complex128{1 + 2i}, 856 | } 857 | computed := ConjugateMatrix(complexMatrix) 858 | actual := [][]complex128{ 859 | []complex128{1 - 2i}, 860 | } 861 | for ii := 0; ii < len(computed); ii++ { 862 | for jj := 0; jj < len(computed); jj++ { 863 | if computed[ii][jj] != actual[ii][jj] { 864 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 865 | } 866 | } 867 | } 868 | 869 | complexMatrix = [][]complex128{ 870 | []complex128{3 + 4i, 5 + 7i}, 871 | []complex128{2 + 3i, 4 + 9i}, 872 | } 873 | computed = ConjugateMatrix(complexMatrix) 874 | actual = [][]complex128{ 875 | []complex128{3 - 4i, 5 - 7i}, 876 | []complex128{2 - 3i, 4 - 9i}, 877 | } 878 | for ii := 0; ii < len(computed); ii++ { 879 | for jj := 0; jj < len(computed); jj++ { 880 | if computed[ii][jj] != actual[ii][jj] { 881 | t.Errorf("Actual value: %f, computed value: %f, in the position: [%d][%d]", actual[ii][jj], computed[ii][jj], ii, jj) 882 | } 883 | } 884 | } 885 | 886 | } 887 | --------------------------------------------------------------------------------