Files
Euler/Tests/EulerTests/MatrixTest.swift
2020-03-04 13:24:12 -05:00

1056 lines
30 KiB
Swift

//
// File.swift
//
//
// Created by Arthur Guiot on 2020-03-04.
//
import Foundation
import XCTest
import Euler
#if os(macOS)
class MatrixTests: XCTestCase {
func assertEqual(_ m1: Matrix, _ m2: Matrix) {
XCTAssertEqual(m1.rows, m2.rows)
XCTAssertEqual(m1.columns, m2.columns)
for r in 0..<m1.rows {
for c in 0..<m1.columns {
XCTAssertEqual(m1[r, c], m2[r, c])
}
}
}
func assertEqual(_ m1: Matrix, _ m2: Matrix, accuracy epsilon: Double) {
XCTAssertEqual(m1.rows, m2.rows)
XCTAssertEqual(m1.columns, m2.columns)
for r in 0..<m1.rows {
for c in 0..<m1.columns {
XCTAssertEqual(m1[r, c], m2[r, c], accuracy: epsilon)
}
}
}
/*
Since Matrix is a struct, if you copy the matrix to another variable,
Swift doesn't actually copy the memory until you modify the new variable.
Because Matrix uses Accelerate framework to modify its contents, we want
to make sure that it doesn't modify the original array, only the copy.
This helper function forces Swift to make a copy.
*/
func copy(_ m: Matrix) -> Matrix {
var q = m
q[0,0] = m[0,0] // force Swift to make a copy
return q
}
}
// MARK: - Creating matrices
extension MatrixTests {
func testCreateFromArray() {
let a = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
let m = Matrix(a)
XCTAssertEqual(m.rows, a.count)
XCTAssertEqual(m.columns, a[0].count)
for r in 0..<m.rows {
for c in 0..<m.columns {
XCTAssertEqual(m[r, c], a[r][c])
}
}
}
func testCreateFromArrayRange() {
let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]
for i in 0..<3 {
for j in i..<3 {
let m = Matrix(a, range: i...j)
XCTAssertEqual(m.rows, a.count)
XCTAssertEqual(m.columns, j - i + 1)
for r in 0..<m.rows {
for c in i...j {
XCTAssertEqual(m[r, c - i], a[r][c])
}
}
}
}
}
func testCreateFromRowVector() {
let v = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
let m = Matrix(v)
XCTAssertEqual(m.rows, 1)
XCTAssertEqual(m.columns, v.count)
for c in 0..<m.columns {
XCTAssertEqual(m[0, c], v[c])
}
}
func testCreateFromColumnVector() {
let v = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
let m = Matrix(v, isColumnVector: true)
XCTAssertEqual(m.rows, v.count)
XCTAssertEqual(m.columns, 1)
for r in 0..<m.rows {
XCTAssertEqual(m[r, 0], v[r])
}
}
func testCreateRowVectorFromRange() {
let m1 = Matrix(10..<20)
XCTAssertEqual(m1.rows, 10)
for r in 0..<m1.rows {
XCTAssertEqual(m1[r, 0], Double(r + 10))
}
let m2 = Matrix(-10...10)
XCTAssertEqual(m2.rows, 21)
for r in 0..<m2.rows {
XCTAssertEqual(m2[r, 0], Double(-10 + r))
}
}
func testCreateColumnVectorFromRange() {
let m1 = Matrix(10..<20, isColumnVector: true)
XCTAssertEqual(m1.columns, 10)
for c in 0..<m1.columns {
XCTAssertEqual(m1[0, c], Double(c + 10))
}
let m2 = Matrix(-10...10, isColumnVector: true)
XCTAssertEqual(m2.columns, 21)
for c in 0..<m2.columns {
XCTAssertEqual(m2[0, c], Double(-10 + c))
}
}
func testZeros() {
let m = Matrix.zeros(rows: 3, columns: 3)
for r in 0..<3 {
for c in 0..<3 {
XCTAssertEqual(m[r, c], 0)
}
}
}
func testIdentityMatrix() {
let m = Matrix.identity(size: 3)
XCTAssertEqual(m[0, 0], 1)
XCTAssertEqual(m[0, 1], 0)
XCTAssertEqual(m[0, 2], 0)
XCTAssertEqual(m[1, 0], 0)
XCTAssertEqual(m[1, 1], 1)
XCTAssertEqual(m[1, 2], 0)
XCTAssertEqual(m[2, 0], 0)
XCTAssertEqual(m[2, 1], 0)
XCTAssertEqual(m[2, 2], 1)
}
func testTile() {
let v = Matrix([1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
let m = v.tile(5)
XCTAssertEqual(m.rows, 5)
XCTAssertEqual(m.columns, v.columns)
for r in 0..<m.rows {
for c in 0..<m.columns {
XCTAssertEqual(m[r, c], v[c])
}
}
assertEqual(v, v.tile(1))
}
}
// MARK: - Subscripts
extension MatrixTests {
func testChangeMatrixUsingSubscript() {
var m = Matrix.ones(rows: 3, columns: 3)
for r in 0..<3 {
for c in 0..<3 {
m[r, c] = 100*(Double(r)+1) + 10*(Double(c)+1)
}
}
for r in 0..<3 {
for c in 0..<3 {
XCTAssertEqual(m[r, c], 100*(Double(r)+1) + 10*(Double(c)+1))
}
}
}
func testSubscriptRowVector() {
let v = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
let m = Matrix(v)
for c in 0..<m.columns {
XCTAssertEqual(m[c], v[c])
XCTAssertEqual(m[c], m[0, c])
}
}
func testSubscriptColumnVector() {
let v = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
let m = Matrix(v, isColumnVector: true)
for r in 0..<m.rows {
XCTAssertEqual(m[r], v[r])
XCTAssertEqual(m[r], m[r, 0])
}
}
func testSubscriptRowGetter() {
let a = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
let m = Matrix(a)
let M = copy(m)
let r0 = m[row: 0]
XCTAssertEqual(r0[0], 1.0)
XCTAssertEqual(r0[1], 2.0)
let r1 = m[row: 1]
XCTAssertEqual(r1[0], 3.0)
XCTAssertEqual(r1[1], 4.0)
let r2 = m[row: 2]
XCTAssertEqual(r2[0], 5.0)
XCTAssertEqual(r2[1], 6.0)
assertEqual(m, M)
}
func testSubscriptRowSetter() {
let a = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
var m = Matrix(a)
m[row: 0] = Matrix([-1, -2])
XCTAssertEqual(m[0, 0], -1.0)
XCTAssertEqual(m[0, 1], -2.0)
m[row: 1] = Matrix([-3, -4])
XCTAssertEqual(m[1, 0], -3.0)
XCTAssertEqual(m[1, 1], -4.0)
m[row: 2] = Matrix([-5, -6])
XCTAssertEqual(m[2, 0], -5.0)
XCTAssertEqual(m[2, 1], -6.0)
}
func testSubscriptRowsGetter() {
let a = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]
let m = Matrix(a)
let M = copy(m)
let r0 = m[rows: 0...0]
XCTAssertEqual(r0.rows, 1)
XCTAssertEqual(r0.columns, 3)
XCTAssertEqual(r0[0, 0], 1.0)
XCTAssertEqual(r0[0, 1], 2.0)
XCTAssertEqual(r0[0, 2], 3.0)
let r1 = m[rows: 0...1]
XCTAssertEqual(r1.rows, 2)
XCTAssertEqual(r1.columns, 3)
XCTAssertEqual(r1[0, 0], 1.0)
XCTAssertEqual(r1[0, 1], 2.0)
XCTAssertEqual(r1[0, 2], 3.0)
XCTAssertEqual(r1[1, 0], 4.0)
XCTAssertEqual(r1[1, 1], 5.0)
XCTAssertEqual(r1[1, 2], 6.0)
let r2 = m[rows: 0...2]
assertEqual(r2, m)
let r3 = m[rows: 1...2]
XCTAssertEqual(r3.rows, 2)
XCTAssertEqual(r3.columns, 3)
XCTAssertEqual(r3[0, 0], 4.0)
XCTAssertEqual(r3[0, 1], 5.0)
XCTAssertEqual(r3[0, 2], 6.0)
XCTAssertEqual(r3[1, 0], 7.0)
XCTAssertEqual(r3[1, 1], 8.0)
XCTAssertEqual(r3[1, 2], 9.0)
let r4 = m[rows: 2...2]
XCTAssertEqual(r4.rows, 1)
XCTAssertEqual(r4.columns, 3)
XCTAssertEqual(r4[0, 0], 7.0)
XCTAssertEqual(r4[0, 1], 8.0)
XCTAssertEqual(r4[0, 2], 9.0)
assertEqual(m, M)
}
func testSubscriptRowsSetter() {
var m = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
m[rows: 0...0] = Matrix([-1, -2, -3])
assertEqual(m, Matrix([[-1, -2, -3], [4, 5, 6], [7, 8, 9]]))
m[rows: 0...1] = Matrix([[10, 20, 30], [-4, -5, -6]])
assertEqual(m, Matrix([[10, 20, 30], [-4, -5, -6], [7, 8, 9]]))
m[rows: 0...2] = Matrix([[-10, -20, -30], [40, 50, 60], [-7, -8, -9]])
assertEqual(m, Matrix([[-10, -20, -30], [40, 50, 60], [-7, -8, -9]]))
m[rows: 1...2] = Matrix([[-40, -50, -60], [70, 80, 90]])
assertEqual(m, Matrix([[-10, -20, -30], [-40, -50, -60], [70, 80, 90]]))
m[rows: 2...2] = Matrix([-70, -80, -90])
assertEqual(m, Matrix([[-10, -20, -30], [-40, -50, -60], [-70, -80, -90]]))
}
func testSubscriptRowIndicesGetter() {
let m = Matrix([[1, 2], [3, 4], [5, 6]])
let M = copy(m)
assertEqual(m[rows: [0]], [1, 2])
assertEqual(m[rows: [1]], [3, 4])
assertEqual(m[rows: [2]], [5, 6])
assertEqual(m[rows: [0, 1]], Matrix([[1, 2], [3, 4]]))
assertEqual(m[rows: [1, 0]], Matrix([[3, 4], [1, 2]]))
assertEqual(m[rows: [0, 2]], Matrix([[1, 2], [5, 6]]))
assertEqual(m[rows: [2, 0]], Matrix([[5, 6], [1, 2]]))
assertEqual(m[rows: [2, 1, 0]], Matrix([[5, 6], [3, 4], [1, 2]]))
assertEqual(m, M)
}
func testSubscriptColumnGetter() {
let a = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
let m = Matrix(a)
let M = copy(m)
let c0 = m[column: 0]
XCTAssertEqual(c0[0], 1.0)
XCTAssertEqual(c0[1], 3.0)
XCTAssertEqual(c0[2], 5.0)
let c1 = m[column: 1]
XCTAssertEqual(c1[0], 2.0)
XCTAssertEqual(c1[1], 4.0)
XCTAssertEqual(c1[2], 6.0)
assertEqual(m, M)
}
func testSubscriptColumnSetter() {
let a = [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]
var m = Matrix(a)
m[column: 0] = Matrix([-1, -3, -5], isColumnVector: true)
XCTAssertEqual(m[0, 0], -1.0)
XCTAssertEqual(m[1, 0], -3.0)
XCTAssertEqual(m[2, 0], -5.0)
m[column: 1] = Matrix([-2, -4, -6], isColumnVector: true)
XCTAssertEqual(m[0, 1], -2.0)
XCTAssertEqual(m[1, 1], -4.0)
XCTAssertEqual(m[2, 1], -6.0)
}
func testSubscriptColumnsGetter() {
let a = [[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]]
let m = Matrix(a)
let M = copy(m)
let r0 = m[columns: 0...0]
XCTAssertEqual(r0.rows, 3)
XCTAssertEqual(r0.columns, 1)
XCTAssertEqual(r0[0, 0], 1.0)
XCTAssertEqual(r0[1, 0], 2.0)
XCTAssertEqual(r0[2, 0], 3.0)
let r1 = m[columns: 0...1]
XCTAssertEqual(r1.rows, 3)
XCTAssertEqual(r1.columns, 2)
XCTAssertEqual(r1[0, 0], 1.0)
XCTAssertEqual(r1[1, 0], 2.0)
XCTAssertEqual(r1[2, 0], 3.0)
XCTAssertEqual(r1[0, 1], 4.0)
XCTAssertEqual(r1[1, 1], 5.0)
XCTAssertEqual(r1[2, 1], 6.0)
let r2 = m[columns: 0...2]
assertEqual(r2, m)
let r3 = m[columns: 1...2]
XCTAssertEqual(r3.rows, 3)
XCTAssertEqual(r3.columns, 2)
XCTAssertEqual(r3[0, 0], 4.0)
XCTAssertEqual(r3[1, 0], 5.0)
XCTAssertEqual(r3[2, 0], 6.0)
XCTAssertEqual(r3[0, 1], 7.0)
XCTAssertEqual(r3[1, 1], 8.0)
XCTAssertEqual(r3[2, 1], 9.0)
let r4 = m[columns: 2...2]
XCTAssertEqual(r4.rows, 3)
XCTAssertEqual(r4.columns, 1)
XCTAssertEqual(r4[0, 0], 7.0)
XCTAssertEqual(r4[1, 0], 8.0)
XCTAssertEqual(r4[2, 0], 9.0)
assertEqual(m, M)
}
func testSubscriptColumnsSetter() {
var m = Matrix([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
m[columns: 0...0] = Matrix([[-1], [-2], [-3]])
assertEqual(m, Matrix([[-1, 4, 7], [-2, 5, 8], [-3, 6, 9]]))
m[columns: 0...1] = Matrix([[10, -4], [20, -5], [30, -6]])
assertEqual(m, Matrix([[10, -4, 7], [20, -5, 8], [30, -6, 9]]))
m[columns: 0...2] = Matrix([[-10, 40, -7], [-20, 50, -8], [-30, 60, -9]])
assertEqual(m, Matrix([[-10, 40, -7], [-20, 50, -8], [-30, 60, -9]]))
m[columns: 1...2] = Matrix([[-40, 70], [-50, 80], [-60, 90]])
assertEqual(m, Matrix([[-10, -40, 70], [-20, -50, 80], [-30, -60, 90]]))
m[columns: 2...2] = Matrix([[-70], [-80], [-90]])
assertEqual(m, Matrix([[-10, -40, -70], [-20, -50, -80], [-30, -60, -90]]))
}
func testSubscriptScalar() {
let a1 = [[7.0, 6.0], [5.0, 4.0], [3.0, 2.0]]
let m1 = Matrix(a1)
XCTAssertEqual(m1.scalar, a1[0][0])
let a2 = [[9.0]]
let m2 = Matrix(a2)
XCTAssertEqual(m2.scalar, a2[0][0])
}
func testToArray() {
let a:[[Double]] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]
let m = Matrix(a)
XCTAssertEqual(m.array, a)
}
}
// MARK: - Operations
extension MatrixTests {
func testInverse() {
let m = Matrix([[1, 2, 3], [0, 4, 0], [3, 2, 1]])
let M = copy(m)
let i = m.inverse()
XCTAssertEqual(m.rows, i.rows)
XCTAssertEqual(m.columns, i.columns)
XCTAssertEqual(i[0, 0], -0.125)
XCTAssertEqual(i[0, 1], -0.125)
XCTAssertEqual(i[0, 2], 0.375)
XCTAssertEqual(i[1, 0], 0)
XCTAssertEqual(i[1, 1], 0.25)
XCTAssertEqual(i[1, 2], 0)
XCTAssertEqual(i[2, 0], 0.375)
XCTAssertEqual(i[2, 1], -0.125)
XCTAssertEqual(i[2, 2], -0.125)
let o = i.inverse()
assertEqual(m, o)
// make sure accelerate framework magic didn't overwrite the original
assertEqual(m, M)
}
func testInverseIdentityMatrix() {
let m = Matrix.identity(size: 3)
let i = m.inverse()
assertEqual(m, i)
}
func testInverseSingularMatrix() {
// Note: currently non-invertible matrices give an assertion.
// Either trap that with a test (how?), or maybe return nil?
}
func testTranspose() {
let m = Matrix([[1, 2], [3, 4], [5, 6]])
let M = copy(m)
let t = m.transpose()
XCTAssertEqual(m.rows, t.columns)
XCTAssertEqual(m.columns, t.rows)
for r in 0..<m.rows {
for c in 0..<m.columns {
XCTAssertEqual(m[r, c], t[c, r])
}
}
let o = t.transpose()
assertEqual(m, o)
assertEqual(m, M)
}
}
// MARK: - Arithmetic
extension MatrixTests {
func testAddMatrixMatrix() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let c = Matrix([[11, 22], [33, 44], [55, 66]])
let A = copy(a)
let B = copy(b)
assertEqual(a + b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testAddMatrixRowVector() {
let a = Matrix([[10, 20], [30, 40], [50, 60]])
let b = Matrix([5, 10])
let c = Matrix([[15, 30], [35, 50], [55, 70]])
let A = copy(a)
let B = copy(b)
assertEqual(a + b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testAddMatrixColumnVector() {
let a = Matrix([[10, 20], [30, 40], [50, 60]])
let b = Matrix([5, 10, 1], isColumnVector: true)
let c = Matrix([[15, 25], [40, 50], [51, 61]])
let A = copy(a)
let B = copy(b)
assertEqual(a + b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testAddMatrixScalar() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[11, 12], [13, 14], [15, 16]])
let A = copy(a)
assertEqual(a + 10, b)
assertEqual(10 + a, b)
assertEqual(a, A)
}
func testSubtractMatrixMatrix() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let c = Matrix([[ 9, 18], [27, 36], [45, 54]])
let A = copy(a)
let B = copy(b)
assertEqual(b - a, c)
assertEqual(a, A)
assertEqual(b, B)
let d = Matrix([[-9, -18], [-27, -36], [-45, -54]])
assertEqual(a - b, d)
assertEqual(a, A)
assertEqual(b, B)
}
func testSubtractMatrixRowVector() {
let a = Matrix([[10, 20], [30, 40], [50, 60]])
let b = Matrix([5, 10])
let c = Matrix([[5, 10], [25, 30], [45, 50]])
let A = copy(a)
let B = copy(b)
assertEqual(a - b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testSubtractMatrixColumnVector() {
let a = Matrix([[10, 20], [30, 40], [50, 60]])
let b = Matrix([5, 10, 1], isColumnVector: true)
let c = Matrix([[5, 15], [20, 30], [49, 59]])
let A = copy(a)
let B = copy(b)
assertEqual(a - b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testSubtractMatrixScalar() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[11, 12], [13, 14], [15, 16]])
let B = copy(b)
assertEqual(b - 10, a)
let c = Matrix([[-1, -2], [-3, -4], [-5, -6]])
assertEqual(10 - b, c)
assertEqual(b, B)
}
func testNegateMatrix() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[-1, -2], [-3, -4], [-5, -6]])
let A = copy(a)
let B = copy(b)
assertEqual(-a, b)
assertEqual(-b, a)
assertEqual(a, A)
assertEqual(b, B)
}
func testMultiplyMatrixMatrix() {
let a = Matrix([[1, 2], [3, 4], [5, 6]]) // 3x2
let b = Matrix([[10], [20]]) // 2x1
let c = Matrix([[50], [110], [170]]) // 3x1
let A = copy(a)
let B = copy(b)
assertEqual(a <*> b, c)
assertEqual(a, A)
assertEqual(b, B)
let d = Matrix([[10, 20, 30], [40, 50, 60]]) // 2x3
let e = Matrix([[90, 120, 150], [190, 260, 330], [290, 400, 510]]) // 3x3
let f = Matrix([[220, 280], [490, 640]]) // 2x2
let D = d
assertEqual(a <*> d, e)
assertEqual(d <*> a, f)
assertEqual(a, A)
assertEqual(d, D)
let i = Matrix.identity(size: 2) // 2x2
let j = Matrix.identity(size: 3) // 3x3
assertEqual(a <*> i, a)
assertEqual(j <*> a, a)
}
func testMultiplyMatrixMatrixElementwise() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let c = Matrix([[10, 40], [90, 160], [250, 360]])
let A = copy(a)
let B = copy(b)
assertEqual(a * b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testMultiplyMatrixRowVector() {
let a = Matrix([[2, 5], [6, 10], [12, 20]])
let b = Matrix([5, 4])
let c = Matrix([[10, 20], [30, 40], [60, 80]])
let A = copy(a)
let B = copy(b)
assertEqual(a * b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testMultiplyMatrixColumnVector() {
let a = Matrix([[2, 4], [2, 3], [6, 8]])
let b = Matrix([5, 15, 10], isColumnVector: true)
let c = Matrix([[10, 20], [30, 45], [60, 80]])
let A = copy(a)
let B = copy(b)
assertEqual(a * b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testMultiplyMatrixScalar() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let A = copy(a)
assertEqual(a * 10, b)
assertEqual(10 * a, b)
assertEqual(a, A)
}
func testDivideMatrixMatrix() {
let a = Matrix([[1, 2], [3, 4], [5, 6]]) // 3x2
let b = Matrix([[5, 6], [7, 8]]) // 2x2
let c = Matrix([[3, -2], [2, -1], [1, 0]]) // 3x2
let A = copy(a)
let B = copy(b)
assertEqual(a </> b, c, accuracy: 1e-10)
assertEqual(a <*> b.inverse(), c, accuracy: 1e-10)
assertEqual(a, A)
assertEqual(b, B)
let i = Matrix.identity(size: 2) // 2x2
assertEqual(a </> i, a)
}
func testDivideMatrixMatrixElementwise() {
let a = Matrix([[10, 40], [90, 160], [250, 360]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let c = Matrix([[1, 2], [3, 4], [5, 6]])
let A = copy(a)
let B = copy(b)
assertEqual(a / b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testDivideMatrixRowVector() {
let a = Matrix([[10, 20], [30, 40], [60, 80]])
let b = Matrix([5, 4])
let c = Matrix([[2, 5], [6, 10], [12, 20]])
let A = copy(a)
let B = copy(b)
assertEqual(a / b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testDivideMatrixColumnVector() {
let a = Matrix([[10, 20], [30, 45], [60, 80]])
let b = Matrix([5, 15, 10], isColumnVector: true)
let c = Matrix([[2, 4], [2, 3], [6, 8]])
let A = copy(a)
let B = copy(b)
assertEqual(a / b, c)
assertEqual(a, A)
assertEqual(b, B)
}
func testDivideMatrixScalar() {
let a = Matrix([[ 1, 2], [ 3, 4], [ 5, 6]])
let b = Matrix([[10, 20], [30, 40], [50, 60]])
let c = Matrix([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])
let A = copy(a)
let B = copy(b)
assertEqual(a / 10, c, accuracy: 1e-10)
assertEqual(b / 10, a)
assertEqual(a, A)
assertEqual(b, B)
let d = Matrix([[10.0, 5], [10.0/3, 2.5], [2, 10.0/6]])
assertEqual(10 / a, d, accuracy: 1e-10)
}
}
// MARK: - Other maths
extension MatrixTests {
func testExp() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[2.7182818285, 7.3890560989], [20.0855369232, 54.5981500331], [148.4131591026, 403.4287934927]])
let A = copy(a)
assertEqual(a.exp(), b, accuracy: 1e-10)
assertEqual(a, A)
}
func testLog() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[0.0000000000, 0.6931471806], [1.0986122887, 1.3862943611], [1.6094379124, 1.7917594692]])
let A = copy(a)
assertEqual(a.log(), b, accuracy: 1e-10)
assertEqual(a, A)
}
func testPow() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[1, 4], [9, 16], [25, 36]])
let c = Matrix([[1.0000000000, 1.4142135624], [1.7320508076, 2.0000000000], [2.2360679775, 2.4494897428]])
let A = copy(a)
assertEqual(a.pow(2), b, accuracy: 1e-10)
assertEqual(a.pow(0.5), c, accuracy: 1e-10)
assertEqual(a, A)
}
func testSqrt() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([[1, 4], [9, 16], [25, 36]])
let A = copy(a)
assertEqual(b.sqrt(), a, accuracy: 1e-10)
assertEqual(a.sqrt(), a.pow(0.5), accuracy: 1e-10)
assertEqual(a, A)
}
func testSumAll() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let A = copy(a)
XCTAssertEqual(a.sum(), 21)
assertEqual(a, A)
let b = Matrix([[-1, -2], [-3, -4], [-5, -6]])
XCTAssertEqual(b.sum(), -21)
let i = Matrix.identity(size: 10)
XCTAssertEqual(i.sum(), 10)
let z = Matrix.zeros(rows: 10, columns: 20)
XCTAssertEqual(z.sum(), 0)
let o = Matrix.ones(rows: 50, columns: 50)
XCTAssertEqual(o.sum(), 2500)
}
func testSumRows() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([3, 7, 11], isColumnVector: true)
let A = copy(a)
assertEqual(a.sumRows(), b)
assertEqual(a, A)
}
func testSumColumns() {
let a = Matrix([[1, 2], [3, 4], [5, 6]])
let b = Matrix([9, 12])
let A = copy(a)
assertEqual(a.sumColumns(), b)
assertEqual(a, A)
}
}
// MARK: - Minimum and maximum
extension MatrixTests {
func testMinRow() {
let a = Matrix([[19, 7, 21], [3, 40, 15], [5, 4, -1]])
let A = copy(a)
let r0 = a.min(row: 0)
XCTAssertEqual(r0.0, 7)
XCTAssertEqual(r0.1, 1)
let r1 = a.min(row: 1)
XCTAssertEqual(r1.0, 3)
XCTAssertEqual(r1.1, 0)
let r2 = a.min(row: 2)
XCTAssertEqual(r2.0, -1)
XCTAssertEqual(r2.1, 2)
assertEqual(a, A)
}
func testMaxRow() {
let a = Matrix([[19, 7, 21], [3, 40, 15], [5, 4, -1]])
let A = copy(a)
let r0 = a.max(row: 0)
XCTAssertEqual(r0.0, 21)
XCTAssertEqual(r0.1, 2)
let r1 = a.max(row: 1)
XCTAssertEqual(r1.0, 40)
XCTAssertEqual(r1.1, 1)
let r2 = a.max(row: 2)
XCTAssertEqual(r2.0, 5)
XCTAssertEqual(r2.1, 0)
assertEqual(a, A)
}
func testMinRows() {
let a = Matrix([[19, 7, 21], [3, 40, 15], [5, 4, -1]])
let b = Matrix([7, 3, -1], isColumnVector: true)
let A = copy(a)
assertEqual(a.minRows(), b)
assertEqual(a, A)
}
func testMaxRows() {
let a = Matrix([[19, 7, 21], [3, 40, 15], [5, 4, -1]])
let b = Matrix([21, 40, 5], isColumnVector: true)
let A = copy(a)
assertEqual(a.maxRows(), b)
assertEqual(a, A)
}
func testMinColumn() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 21]])
let A = copy(a)
let r0 = a.min(column: 0)
XCTAssertEqual(r0.0, 3)
XCTAssertEqual(r0.1, 1)
let r1 = a.min(column: 1)
XCTAssertEqual(r1.0, 4)
XCTAssertEqual(r1.1, 2)
let r2 = a.min(column: 2)
XCTAssertEqual(r2.0, -1)
XCTAssertEqual(r2.1, 0)
assertEqual(a, A)
}
func testMaxColumn() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 21]])
let A = copy(a)
let r0 = a.max(column: 0)
XCTAssertEqual(r0.0, 19)
XCTAssertEqual(r0.1, 0)
let r1 = a.max(column: 1)
XCTAssertEqual(r1.0, 40)
XCTAssertEqual(r1.1, 1)
let r2 = a.max(column: 2)
XCTAssertEqual(r2.0, 21)
XCTAssertEqual(r2.1, 2)
assertEqual(a, A)
}
func testMinColumns() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 21]])
let b = Matrix([3, 4, -1])
let A = copy(a)
assertEqual(a.minColumns(), b)
assertEqual(a, A)
}
func testMaxColumns() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 21]])
let b = Matrix([19, 40, 21])
let A = copy(a)
assertEqual(a.maxColumns(), b)
assertEqual(a, A)
}
func testMin() {
let a = Matrix([[19, 7, 15], [3, 40, -1], [5, 4, 21]])
let A = copy(a)
let r = a.min()
XCTAssertEqual(r.0, -1)
XCTAssertEqual(r.1, 1)
XCTAssertEqual(r.2, 2)
assertEqual(a, A)
}
func testMax() {
let a = Matrix([[19, 7, -1], [3, 4, 15], [5, 40, 21]])
let A = copy(a)
let r = a.max()
XCTAssertEqual(r.0, 40)
XCTAssertEqual(r.1, 2)
XCTAssertEqual(r.2, 1)
assertEqual(a, A)
}
}
// MARK: - Statistics
extension MatrixTests {
func testMean() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 22]])
let A = copy(a)
assertEqual(a.mean(), [9, 17, 12])
assertEqual(a.mean(0...0), [9, 0, 0])
assertEqual(a.mean(1...1), [0, 17, 0])
assertEqual(a.mean(2...2), [0, 0, 12])
assertEqual(a.mean(0...1), [9, 17, 0])
assertEqual(a.mean(1...2), [0, 17, 12])
assertEqual(a.mean(0...2), [9, 17, 12])
assertEqual(a, A)
}
func testStandardDeviation() {
let a = Matrix([[19, 7, -1], [3, 40, 15], [5, 4, 22]])
let A = copy(a)
assertEqual(a.std(), [8.7177978871, 19.9749843554, 11.7898261226], accuracy: 1e-10)
assertEqual(a, A)
}
}
// MARK: - Performance
extension MatrixTests {
func testPerfCreateFromArrayRange() {
var a = [[Double]]()
for _ in 0..<1000 {
a.append([Double](repeating: Double.pi, count: 1000))
}
measure() {
for _ in 1...10 {
let _ = Matrix(a, range: 0..<1000)
}
}
}
func testPerfTile() {
let v = Matrix.random(rows: 1, columns: 1000)
measure() {
for _ in 1...10 {
let _ = v.tile(2000)
}
}
}
func testCopyEntireMatrix() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
for _ in 1...10 {
let _ = M[rows: Array(0..<1000)]
}
}
}
func testPerfSubscriptRowGetter() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
for _ in 1...10 {
for i in 0..<M.rows {
let _ = M[row: i]
}
}
}
}
func testPerfSubscriptRowSetter() {
var M = Matrix.random(rows: 1000, columns: 1000)
let v = Matrix.random(rows: 1, columns: 1000)
measure() {
for _ in 1...10 {
for i in 0..<M.rows {
M[row: i] = v
}
}
}
}
func testSubscripColumnGetter() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
for _ in 1...10 {
for i in 0..<M.columns {
let _ = M[column: i]
}
}
}
}
func testPerfSubscriptColumnSetter() {
var M = Matrix.random(rows: 1000, columns: 1000)
let v = Matrix.random(rows: 1000, columns: 1)
measure() {
for _ in 1...10 {
for i in 0..<M.columns {
M[column: i] = v
}
}
}
}
func testPerfSqrt() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
for _ in 1...10 {
let _ = M.sqrt()
}
}
}
func testPow2() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
let _ = M.pow(2)
}
}
func testPow3() {
let M = Matrix.random(rows: 1000, columns: 1000)
measure() {
let _ = M.pow(3)
}
}
}
#endif