【何を血迷ったか】Swift に簡単な「行列」を実装してみた話

# 行列 #とは
大体のことは [Wikipedia 先生](https://ja.wikipedia.org/wiki/行列)が教えてくれますが、まあ学校でちゃんと習ってないとなんか言ってることがわからないよね。でもまあぶっちゃけそんなクソ面倒なことやるつもりはないし、ちゃんとした行列や行列式などの演算をやりたいなら [swix](https://github.com/stsievert/swix) などのフレームワークもあるので、これはどっちかというと本当に「すべての行は同じ要素数が入ってる」という行列の基本性質を満たしたただの 2 次元配列のデータに過ぎないんじゃないかと思われ。そしてそれを手軽に利用できたらなぁと思っただけです。

# 目標
1. 2 次元配列から行列を作れる
2. 行列の特定要素（数学でいう「(i, j) 番目の要素」）を取得／修正できる
3. 簡単な行列編集（行の追加／削除、列の追加／削除）ができる
4. 簡単な行列演算（足し算、引き算、スカラー掛け算、行列掛け算、転置行列）ができる

くらいかな？

# 実装
まあまず作るも何も、「行列」というものを定義してやんないと話が始まらん。というわけでまず「行列」というやらを定義してあげます。

```swift:Matrix.swift
public struct Matrix <Element> {
	
	fileprivate var _value: [Element]
	fileprivate var _columns: Int
	fileprivate var _rows: Int
	
}
```

以上で「行列」というやらの基本定義ができました。これは要するに `Array<Element>` と同じように、`Matrix<Element>` と言う `Element` 型の `Matrix` だよ、ということ。ちなみにデータの構造は結局ただの `Array<Element>`、すなわち `[Element]` だけど、最初の実装は実は `[[Element]]` の二次元配列にしたのです。なぜこれやめたかというと、二次元配列の場合「0 行 8 列」というような、行が 0 だけど列が複数あるという空行列が表現できないので、やっぱり一次元配列にして行数と列数もそれぞれ変数としてもたせてあげた方がいいのでは？という結論に至りました。

でもこれではまだ全ての変数が `fileprivate` になっているので行列を自分で作れないですね。というわけで、次は二次元配列から行列を作るところを実装します

## 2 次元配列から行列を作る

```swift:Matrix.swift
public enum MatrixInitError: Error {
	case rowsWithDifferentColumns
}

public struct Matrix <Element> {
	
	fileprivate var _value: [Element]
	fileprivate var _columns: Int
	fileprivate var _rows: Int
	
	public init(_ array: [[Element]]) throws {
		let rowCount = array.count
		let columnCount = array.first?.count ?? 0
		for row in array {
			guard row.count == columnCount else {
				throw MatrixInitError.rowsWithDifferentColumns
			}
		}
		self._value = array.flatMap { $0 }
		self._columns = columnCount
		self._rows = rowCount
	}
	
}
```

「`Element`」というジェネリック型があるので、どうやら通常の `struct` と違って `Matrix` の下に `enum` が作れない（もしくは作れるかもしれないが別の方法があるかもしれません、教えていただけると大変喜びます）ので仕方なく別のところで `MatrixInitError` という `Error` の `enum` を作ります。そして二次元配列が渡されたら、ちゃんと全ての配列が同じ要素数がどうかを確認して、一致したら二次元配列を一次元配列に直して行数と列数をそれぞれ元の二次元配列の中身の配列数とさらにその中の要素数にし、一致しなかったらエラーを吐き出すスロアブルイニシャライザーを作ります。これでいつでも自分の二次元配列を使って `Matrix([[element]])` で行列が作れます。

ちなみに最初から同じ要素で指定した行数と列数を行列を作るイニシャライザーも作っておきました

```swift:Matrix.swift
public struct Matrix <Element> {
	
	// ...
	
	public typealias Size = (m: Int, n: Int)
	public var size: Size {
		return (self._rows, self._columns)
	}
	
	public init(size: Size, repeatedValue: Element) {
		let elementCount = size.m * size.n
		let elements = (0 ..< elementCount).map { (_) -> Element in
			return repeatedValue
		}
		self._value = elements
		self._columns = size.n
		self._rows = size.m
	}

}

extension Matrix where Element: ExpressibleByIntegerLiteral {
	
	public init(size: Size) {
		self.init(size: size, repeatedValue: 0)
	}
	
}
```

これで `Matrix(size: (n: 5, m: 6))` で 5 列 6 行の全ての要素が 0 の行列が作れます

## 行列の特定要素（数学でいう「(i, j) 番目の要素」）の取得／修正
さてここは強力な `subscript` の出番です。通常の二次元配列なら先に行数、その次に列数を指定するのが普通ですが行列に限っては先に縦から数えた行数 `i`、次に横から数えた列数 `j` を指定するのが普通ですので、下記のように `subscript` を組みます：

```swift:Matrix.swift
public struct Matrix <Element> {
	
	// ...
	
	public typealias Index = (i: Int, j: Int)
	
	public subscript(index: Index) -> Element {
		get {
			let i = index.i, j = index.j
			return self[i, j]
		}
		set {
			let i = index.i, j = index.j
			self[i, j] = newValue
		}
	}
	
	public subscript(i: Int, j: Int) -> Element {
		get {
			let index = i * self._columns + j
			return self._value[index]
		}
		set {
			let index = i * self._columns + j
			self._value[index] = newValue
		}
	}
	
}
```

これで `matrix[Index(i, j)]` もしくは `matrix[0, 1]` で行列の (0, 1) 番目の要素を取り出せます。

ちなみに特定要素だけでなく、特定行や特定列を取り出したいこともあると思って、さらに別の `subscript` も作りました：

```swift:Matrix.swift
public struct Matrix <Element> {
	
	// ...
		
	public typealias Indices = (columns: CountableRange<Int>, rows: CountableRange<Int>)
	public var indices: Indices {
		return (0 ..< self._columns, 0 ..< self._rows)
	}
	
	public subscript(row i: Int) -> [Element] {
		return self.indices.columns.map({ (j) -> Element in
			return self[(i, j)]
		})
	}
	
	public subscript(column j: Int) -> [Element] {
		return self.indices.rows.map({ (i) -> Element in
			return self[(i, j)]
		})
	}
	
}
```

まずは普通の配列と同じ感覚で、`Indices` という範囲型を実装し、それぞれ行範囲と列範囲を定義してあげることで使うときに手軽に範囲が取得できます。

そして `subscript` のラベルは明示的に書かないとラベルとして使えないので、行を取り出すか、列を取り出すかを明示的に `row` と `column` をラベルとして書いてあげています。これで `matrix[column: 0]` で 0 列目を取り出せます。

ちなみにここは要素を取り出す時と違って、セッターが定義されておらずゲッターだけしか実装していません。なぜならば Swift の `subscript` はエラーハンドリングができないので、編集時に行数と列数に厳しい制限のある行列にはそのまま「はいこの行はこの配列で代入してね」っていう行為は非常に危険なのであえて `subscript` にはそれを定義しませんでした。それをやるのは次の章です

## 簡単な行列編集（行の追加／削除、列の追加／削除）ができる
先ほど言った通り、行列は編集時に行数と列数に厳しい制限があるので、エラーハンドリングが必要です。というわけでとりあえずまずエラーを定義しておきます

```swift:Matrix.swift
public enum MatrixMathError: Error {
	case sizeMismatch
}
```

次に編集の内容ですが、とりあえず `Swift.Array` にちなんで、行と列のそれぞれの `append(_:)`、`insert(_: at:)`、`remove(_:)` 系のメソッドと、自分が Eltaso のフレームワークに `Swift.Array` の拡張で追加した `keep(_:)` 系を実装したいと考えています。まずは `append(_:)`

```swift:Matrix.swift
extension Matrix {
	
	public func appendingRow(_ row: [Element]) throws -> Matrix<Element> {
		
		guard row.count == self.size.n else {
			throw MatrixMathError.sizeMismatch
		}
		
		var matrix = self
		matrix._value += row
		matrix._rows.increase()
		return matrix
		
	}
	
	public mutating func appendRow(_ row: [Element]) throws {
		self = try self.appendingRow(row)
	}
	
}

extension Matrix {
	
	public func appendingColumn(_ column: [Element]) throws -> Matrix<Element> {
		
		guard column.count == self.size.m else {
			throw MatrixMathError.sizeMismatch
		}
		
		var matrix = self
		column.enumerated().reversed().forEach { (i, element) in
			matrix._value.insert(element, at: i * self._columns + self._columns)
		}
		matrix._columns.increase()
		
		return matrix
		
	}
	
	public mutating func appendColumn(_ column: [Element]) throws {
		self = try self.appendingColumn(column)
	}
	
}
```

行の追加は非常に簡単で、列のサイズを自分のと比較して合ってるかどうかを確認して、合ってるなら自分の `_value` の後ろに追加して、`_rows` を一つ増やすだけ。問題は列の方がちょっと面倒。一次元配列にとって列の各要素は配列の中にバラバラにあるし、どこかに要素を追加するとそれ以降の要素の場所が全てずれてしまいます。なのでまずは入れる場所を計算して、入れるときは逆順で後ろから入れてあげないと順番がずれてしまいます。

ちなみに上記のソースコードでは `increase()` という命令が使われていますが、これは `Eltaso` のフレームワークの `Swift.Strideable` の拡張で定義したもので、具体的には以下のように実装しています：

```swift:Strideable.swift
extension Strideable {
	
	public var increased: Self {
		return self.advanced(by: 1)
	}
	
	public var decreased: Self {
		return self.advanced(by: -1)
	}
	
	public func increased(by n: Self.Stride) -> Self {
		return self.advanced(by: n)
	}
	
	public func decreased(by n: Self.Stride) -> Self {
		return self.advanced(by: -n)
	}
	
	public mutating func increase(by n: Self.Stride = 1) {
		self = self.increased(by: n)
	}
	
	public mutating func decrease(by n: Self.Stride = 1) {
		self = self.decreased(by: n)
	}
	
}
```

まあ要するに `int += 1` を補完効かせたくて `int.increase()` で書けるようにしたものです。

これで `try matrix.appendColumn([1, 2, 3])` で行列の後ろに `[1, 2, 3]` の列を入れることができます

次に `insert(_: at:)` ですが、同じように行と列それぞれ定義します

```swift:Matrix.swift
extension Matrix {
	
	public func insertingRow(_ row: [Element], at i: Int) throws -> Matrix<Element> {
		
		guard row.count == self.size.n else {
			throw MatrixMathError.sizeMismatch
		}
		
		var matrix = self
		let initialInsertingIndex = i * self._columns
		row.enumerated().forEach { (j, element) in
			matrix._value.insert(element, at: initialInsertingIndex + j)
		}
		matrix._rows.increase()
		return matrix
		
	}
	
	public mutating func insertRow(_ row: [Element], at j: Int) throws {
		self = try self.insertingRow(row, at: j)
	}
	
}

extension Matrix {
	
	public func insertingColumn(_ column: [Element], at j: Int) throws -> Matrix<Element> {
		
		guard column.count == self.size.m else {
			throw MatrixMathError.sizeMismatch
		}
		
		var matrix = self
		column.enumerated().reversed().forEach { (i, element) in
			matrix._value.insert(element, at: i * self._columns + j)
		}
		matrix._columns.increase()
		return matrix
		
	}
	
	public mutating func insertColumn(_ column: [Element], at i: Int) throws {
		self = try self.insertingColumn(column, at: i)
	}
	
}
```

これもさっきの `append(_:)` と同じように、行の追加なら決まった場所に要素をぶち込んでやれば OK ですが、列の場合は逆順で入れてあげないと順番が支離破滅しますので逆順で入れてあげねばなりません。そして入れたら行か列のカウンターを上げてあげなければなりません。

さて次は `remove(_:)` 系ですが、これは `Array` ではさらに `remove(at:)`、`removeFirst(_:)` と `removeLast(_:)` のメソッドがありますので、それぞれの行と列のバージョンを行列に実装します。全部いっぺんに書くと非常に長いのでまずは比較的に簡単な行から

```swift:Matrix.swift
extension Matrix {
	
	public func removingRow(at m: Int) -> Matrix<Element> {
		
		let i = m.limited(within: self.indices.rows)
		
		var matrix = self
		let rows = Array(self.indices.rows).filter { (row) -> Bool in
			return row != i
		}.map { (i) -> [Element] in
			return self.indices.columns.map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._rows.decrease()
		
		return matrix
		
	}
	
	public func removingFirstRows(of m: Int) -> Matrix<Element> {
		
		let m = m.limited(within: 0 ... self.size.m)
		
		var matrix = self
		let rows = (self._rows - m ..< self._rows).map { (i) -> [Element] in
			return self.indices.columns.map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._rows.decrease(by: m)
		
		return matrix
		
	}
	
	public func removingLastRows(of m: Int) -> Matrix<Element> {
		
		let m = m.limited(within: 0 ... self.size.m)
		
		var matrix = self
		let rows = (0 ..< m).map { (i) -> [Element] in
			return self.indices.columns.map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._rows.decrease(by: m)
		
		return matrix
		
	}
	
	public mutating func removeRow(at m: Int) {
		self = self.removingRow(at: m)
	}
	
	public mutating func removeFirstRows(of m: Int) {
		self = self.removingFirstRows(of: m)
	}
	
	public mutating func removeLastRows(of m: Int) {
		self = self.removingLastRows(of: m)
	}
	
}
```

ここではまたさらにいきなり独自実装の `limited(within:)` のメソッドが出てきてますが、これも Eltaso では下記のように実装されています：

```swift:Int.swift
extension Int {
	
	public func limited(within range: Range<Int>) -> Int {
		
		switch self {
		case Int.min ... range.lowerBound:
			return range.lowerBound
			
		case range.upperBound.decreased ... Int.max:
			return range.upperBound.decreased
			
		default:
			return self
		}
		
	}
	
	public func limited(within range: ClosedRange<Int>) -> Int {
		
		switch self {
		case Int.min ... range.lowerBound:
			return range.lowerBound
			
		case range.upperBound ... Int.max:
			return range.upperBound
			
		default:
			return self
		}
		
	}
	
	public func limited(within range: CountableRange<Int>) -> Int {
		let range = Range(range)
		return self.limited(within: range)
	}
	
	public func limited(within range: CountableClosedRange<Int>) -> Int {
		let range = ClosedRange(range)
		return self.limited(within: range)
	}
	
	public mutating func limit(within range: Range<Int>) {
		self = self.limited(within: range)
	}
	
	public mutating func limit(within range: ClosedRange<Int>) {
		self = self.limited(within: range)
	}
	
	public mutating func limit(within range: CountableRange<Int>) {
		self = self.limited(within: range)
	}
	
	public mutating func limit(within range: CountableClosedRange<Int>) {
		self = self.limited(within: range)
	}
	
}
```

まあこれは要するに `let a = b <= 0 ? 0 : b >= 10 ? 9 : b` という書くのも面倒だし改行しないと読むのもクソだるいものを `a = b.limited(within: 0 ..< 10)` に書き直せるメソッドです。このメソッドで何をしたいかというと、渡された行数がきちんとこの行列の中の行に入っている、仮にもし入っていなかったらそれに最も近い行に直すということです。

そして `removeRow(at:)` は行列の指定した行を削除し、`removeFirstRows(of:)` は指定した先頭 m 行を削除し、`removeLastRows(of:)` は指定した末尾 m 行を削除するメソッドです。基本的なアプローチは行と列をそれぞれ走査して、必要なものだけ残して `_value` と `_rows` を書き換える感じです。

次にこれの列版を下記のように実装します：

```swift:Matrix.swift
extension Matrix {
	
	public func removingColumn(at n: Int) -> Matrix<Element> {
		
		let j = n.limited(within: self.indices.columns)
		
		var matrix = self
		let rows = self.indices.rows.map { (i) -> [Element] in
			return Array(self.indices.columns).filter({ (column) -> Bool in
				return column != j
			}).map({ (i) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._columns.decrease()
		
		return matrix
		
	}
	
	public func removingFirstColumns(of n: Int) -> Matrix<Element> {
		
		let n = n.limited(within: 0 ... self.size.n)
		
		var matrix = self
		let rows = self.indices.rows.map { (i) -> [Element] in
			return (n ..< self._columns).map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._columns.decrease(by: n)
		
		return matrix
		
	}
	
	public func removingLastColumns(of n: Int) -> Matrix<Element> {
		
		let n = n.limited(within: 0 ... self.size.n)
		
		var matrix = self
		let rows = self.indices.rows.map { (i) -> [Element] in
			return (0 ..< self._columns - n).map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._columns.decrease(by: n)
		
		return matrix
		
	}
	
	public mutating func removeColumn(at n: Int) {
		self = self.removingColumn(at: n)
	}
	
	public mutating func removeFirstColumns(of n: Int) {
		self = self.removingFirstColumns(of: n)
	}
	
	public mutating func removeLastColumns(of n: Int) {
		self = self.removingLastColumns(of: n)
	}
	
}
```

メソッドは行版とほぼ同じで、`Row` が `Column` になっただけです。そして中身のアプローチも概ね行版とそんなに変わってなく、書き換えるのが `_rows` ではなく `_columns` になっただけです

そして最後は Eltaso のフレームワークで独自に追加した `keep(_:)` 系のものですが、これは要するに `remove(_:)` 系と真逆な操作なので、アプローチとしては全く同じで必要か必要ないかの判定を逆にするだけで済みます

```swift:Matrix.swift
extension Matrix {
	
	public func keepingRow(at m: Int) -> Matrix<Element> {
		
		let i = m.limited(within: self.indices.rows)
		
		var matrix = self
		let row = matrix.indices.columns.map({ (j) -> Element in
			return matrix[i, j]
		})
		matrix._value = row
		matrix._rows = 1
		
		return matrix
		
	}
	
	public func keepingFirstRows(of m: Int) -> Matrix<Element> {
		
		let m = m.limited(within: 0 ... self.size.m)
		
		var matrix = self
		let rows = (0 ..< m).map { (i) -> [Element] in
			return self.indices.columns.map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._rows = m
		
		return matrix
		
	}
	
	public func keepingLastRows(of m: Int) -> Matrix<Element> {
		
		let m = m.limited(within: 0 ... self.size.m)
		
		var matrix = self
		let rows = (self._rows - m ..< self._rows).map { (i) -> [Element] in
			return self.indices.columns.map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._rows = m
		
		return matrix
		
	}
	
	public mutating func keepRow(at m: Int) {
		self = self.keepingRow(at: m)
	}
	
	public mutating func keepFirstRows(of m: Int) {
		self = self.keepingFirstRows(of: m)
	}
	
	public mutating func keepLastRows(of m: Int) {
		self = self.keepingLastRows(of: m)
	}
	
}

extension Matrix {
	
	public func keepingColumn(at n: Int) -> Matrix<Element> {
		
		let j = n.limited(within: self.indices.columns)
		
		var matrix = self
		let column = self.indices.rows.map { (i) -> Element in
			return matrix[i, j]
		}
		matrix._value = column
		matrix._columns = 1
		
		return matrix
		
	}
	
	public func keepingFirstColumns(of n: Int) -> Matrix<Element> {
		
		let n = n.limited(within: 0 ... self.size.n)
		
		var matrix = self
		let rows = self.indices.rows.map { (i) -> [Element] in
			return (0 ..< n).map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._columns = n
		
		return matrix
		
	}
	
	public func keepingLastColumns(of n: Int) -> Matrix<Element> {
		
		let n = n.limited(within: 0 ... self.size.n)
		
		var matrix = self
		let rows = self.indices.rows.map { (i) -> [Element] in
			return (self._columns - n ..< self._columns).map({ (j) -> Element in
				return matrix[i, j]
			})
		}
		matrix._value = rows.flatten
		matrix._columns = n
		
		return matrix
		
	}
	
	public mutating func keepColumn(at n: Int) {
		self = self.keepingColumn(at: n)
	}
	
	public mutating func keepFirstColumns(of n: Int) {
		self = self.keepingFirstColumns(of: n)
	}
	
	public mutating func keepLastColumns(of n: Int) {
		self = self.keepingLastColumns(of: n)
	}
	
}
```

## 簡単な行列演算（足し算、引き算、スカラー掛け算、行列掛け算、転置行列）
まあまずは一番簡単な足し算／引き算にしましょうか。これは[行列の和演算定義](https://ja.wikipedia.org/wiki/行列#.E5.92.8C)を見ればわかるように非常に単純なもので、行数と列数がそれぞれ一致する二つの行列を同じ場所の要素を足す／引くだけで済みます。ただ行数／列数は必ず一致しないといけないので、さっきの行列編集と同じようにエラーハンドリングが必要ですね。

```swift:Matrix.swift
public func + <T> (lhs: Matrix<T>, rhs: Matrix<T>) throws -> Matrix<T> where T: AdditionOperatable {
	
	guard lhs.size == rhs.size else {
		throw MatrixMathError.sizeMismatch
	}
	
	var matrix = lhs
	for i in matrix.indices.rows {
		for j in matrix.indices.columns {
			matrix[i, j] += rhs[i, j]
		}
	}
	
	return matrix
	
}

public func += <T> (lhs: inout Matrix<T>, rhs: Matrix<T>) throws where T: AdditionOperatable {
	lhs = try lhs + rhs
}

public func - <T> (lhs: Matrix<T>, rhs: Matrix<T>) throws -> Matrix<T> where T: SubtractionOperatable {
	
	guard lhs.size == rhs.size else {
		throw MatrixMathError.sizeMismatch
	}
	
	var matrix = lhs
	for i in matrix.indices.rows {
		for j in matrix.indices.columns {
			matrix[i, j] -= rhs[i, j]
		}
	}
	
	return matrix
	
}

public func -= <T> (lhs: inout Matrix<T>, rhs: Matrix<T>) throws where T: SubtractionOperatable {
	lhs = try lhs - rhs
}
```

ここもいきなり独自定義の `AdditionOperatable` と `SubtractionOperatable` というやらが出てきてしまってますが、これは Eltaso ではこれらに加えて `MultiplicationOperatable` と `DivisionOperatable` もあり、下記のように定義しています：

```swift:ArithmeticOperatable.swift
public protocol AdditionOperatable {
	static func + (lhs: Self, rhs: Self) -> Self
	static func += ( lhs: inout Self, rhs: Self)
}

public protocol SubtractionOperatable {
	static func - (lhs: Self, rhs: Self) -> Self
	static func -= ( lhs: inout Self, rhs: Self)
}

public protocol MultiplicationOperatable {
	static func * (lhs: Self, rhs: Self) -> Self
	static func *= ( lhs: inout Self, rhs: Self)
}

public protocol DivisionOperatable {
	static func / (lhs: Self, rhs: Self) -> Self
	static func /= ( lhs: inout Self, rhs: Self)
}

extension Int:	AdditionOperatable {}

extension Int: SubtractionOperatable {}

extension Int: MultiplicationOperatable {}

extension Int: DivisionOperatable {}
```

`Int` 型は元から足し算／引き算に対応しているので、単に「こう言う `protocol` を定義したよ、行列演算の時は要素がこの `protocol` に対応していないと行列演算できないよ」という制限を入れただけです。

ちなみに今は `Int` にしか書いてないのです。整数の行列演算にしか手をつけてないのでね…

そして二つの整数行列を足し算したい時、この二つの行列が行数と列数が一致するかを比べ、一致したらそれぞれの要素を足します。まあ簡単ですね、特に言うことはあんまりないのです。

次はスカラー掛け算ですが、これも[行列のスカラー倍演算定義](https://ja.wikipedia.org/wiki/行列#.E3.82.B9.E3.82.AB.E3.83.A9.E3.83.BC.E5.80.8D)を見ると分かりますが非常に簡単です。単純に各要素を指定した数字で掛けるだけです。

```swift:Matrix.swift
public func * <T> (lhs: T, rhs: Matrix<T>) -> Matrix<T> where T: MultiplicationOperatable {
	
	var matrix = rhs
	for j in matrix.indices.rows {
		for i in matrix.indices.columns {
			matrix[i, j] *= lhs
		}
	}
	return matrix
	
}

public func * <T> (lhs: Matrix<T>, rhs: T) -> Matrix<T> where T: MultiplicationOperatable {
	return rhs * lhs
}

public func *= <T> (lhs: inout Matrix<T>, rhs: T) where T: MultiplicationOperatable {
	lhs = lhs * rhs
}
```

さて、問題はこの次の「行列と行列の掛け算」です。これは足し算みたいに、各要素をそのまま掛けてあげればできる演算ではなく、[行列の積演算定義](https://ja.wikipedia.org/wiki/行列#.E7.A9.8D)を読めばわか…らないかもしれないくらい面倒な演算です。まあこればかりはどうしようもない。詳しく知りたい人は行列の教科書でも漁ってみればいいかもしれません。というわけでとりあえず実装を書いておきます：

```swift:Matrix.swift
public func * <T> (lhs: Matrix<T>, rhs: Matrix<T>) throws -> Matrix<T> where T: AdditionOperatable, T: MultiplicationOperatable {
	
	guard lhs.size.n == rhs.size.m else {
		throw MatrixMathError.sizeMismatch
	}
	
	let resultSize: Matrix<T>.Size = (lhs.size.m, rhs.size.n)
	let resultIndices: Matrix<T>.Indices = (lhs.indices.rows, rhs.indices.columns)
	let resultElementFactorIndices: CountableRange<Int> = lhs.indices.columns
	
	func getMultipliedValue(at index: Matrix<T>.Index) -> T {
		return resultElementFactorIndices.reduce(T.additionOperationInitialValue) { (result, indice) -> T in
			let factor = lhs[index.i, indice] * rhs[indice, index.j]
			return result + factor
		}
	}
	
	let value = resultIndices.rows.map { (i) -> [T] in
		return resultIndices.columns.map({ (j) -> T in
			return getMultipliedValue(at: (i, j))
		})
	}
	
	return try Matrix(value)
	
}

public func *= <T> (lhs: inout Matrix<T>, rhs: Matrix<T>) throws where T: AdditionOperatable, T: MultiplicationOperatable {
	lhs = try lhs * rhs
}
```

まあなかなか面倒な計算なので細かい説明は省けますが、足し算とかと同じように各要素を行と列をそれぞれ走査して、`getMultipliedValue(at:)` の関数で結果を求めます。

ちなみにここで `T.additionOperationInitialValue` というやらが出てますが、これは先ほどの `AdditionOperatable` の `protocol` を少し手を加えて求めたものです：

```swift:ArithmeticOperatable.swift
public protocol AdditionOperatable {
	// ...
	static var additionOperationInitialValue: Self { get }
}

extension Int:	AdditionOperatable {
	public static var additionOperationInitialValue: Int {
		return 0
	}
}
```

これは要するに将来 `Int` 型以外を `AdditionOperatable` に対応した時、`reduce(_:_:)` の初期値を代入できるようにするためのものです。

そして最後に転置行列ですが、これは比較的に簡単なものです、要するに行と列を入れ替えた行列です。

```swift:Matrix.swift
extension Matrix {
	
	public var transposed: Matrix {
		
		var transposed = self
		transposed._columns = self._rows
		transposed._rows = self._columns
		
		for i in transposed.indices.rows {
			for j in transposed.indices.columns {
				transposed[i, j] = self[j, i]
			}
		}
		
		return transposed
		
	}
	
	public mutating func transpose() {
		self = self.transposed
	}
	
}
```

まああとはどうせなら行列の比較もやってみたいですね？というわけで比較も作りました

```swift:Matrix.swift
public func == <T> (lhs: Matrix<T>, rhs: Matrix<T>) -> Bool where T: Equatable {
	
	guard lhs.size == rhs.size else {
		return false
	}
	
	for i in 0 ..< lhs.size.m {
		for j in 0 ..< lhs.size.n {
			if lhs[i, j] != rhs[i, j] {
				return false
			}
		}
	}
	
	return true
	
}

public func != <T> (lhs: Matrix<T>, rhs: Matrix<T>) -> Bool where T: Equatable {
	return !(lhs == rhs)
}
```

# あとがき
まあここまで作ったら簡単な行列演算には使えるし、それ以外でも「同じ要素数を持つ各配列から作られた二次元配列」というものにも使えます。もっと手を加えたいのならクソ面倒な行列式とかの対応もできなくはないがそこまでやらなくてもいいじゃないの？と思ったり。最初に言った通りそこまでガチな行列演算をやりたいのなら多分専門的なライブラリーを導入した方がよろしいかと。これはあくまで Eltaso という俺得シュガーシンタックスフレームワークで実現した手軽に使える簡単な行列型ですのでw

そしてフルのソースコードは [Github の Eltaso リポジトリ](https://github.com/el-hoshino/Eltaso/blob/master/Eltaso/Eltaso/Matrix.swift)から確認できます。

あとはご質問とかおツッコミとかどうぞ。