2015-10-06 19:19:59 +03:00
|
|
|
|
/// A two-dimensional matrix of memoized values.
|
|
|
|
|
///
|
|
|
|
|
/// These values are populated by a function from the coordinates of a given cell to the matrix’s element type.
|
2015-10-06 19:20:58 +03:00
|
|
|
|
///
|
|
|
|
|
/// Values are retrieved by subscripting with row/column indices. Out-of-bound indices produce `nil` values, rather than asserting.
|
2015-10-06 20:00:07 +03:00
|
|
|
|
public struct Matrix<A> {
|
|
|
|
|
public init(width: Int, height: Int, compute: (Int, Int) -> A) {
|
2015-11-05 23:45:19 +03:00
|
|
|
|
self.init(width: width, height: height, values: constructRowMajor(0..<width, down: 0..<height, forEach: { i, j in Memo { compute(i, j) } }))
|
2015-11-05 23:45:30 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public init<I: ForwardIndexType>(across: Range<I>, down: Range<I>, compute: (I, I) -> A) {
|
|
|
|
|
self.init(width: Int(across.count.toIntMax()), height: Int(down.count.toIntMax()), values: constructRowMajor(across, down: down, forEach: { i, j in Memo { compute(i, j) } }))
|
2015-10-06 00:12:28 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-10-06 20:00:07 +03:00
|
|
|
|
public let width: Int
|
|
|
|
|
public let height: Int
|
2015-10-06 00:11:56 +03:00
|
|
|
|
|
2015-10-06 20:00:01 +03:00
|
|
|
|
private let values: [Memo<A>]
|
2015-10-06 00:11:56 +03:00
|
|
|
|
|
2015-10-06 20:00:07 +03:00
|
|
|
|
public subscript (i: Int, j: Int) -> Memo<A>? {
|
2015-10-06 00:11:56 +03:00
|
|
|
|
guard i < width && j < height else { return nil }
|
2015-10-06 21:11:36 +03:00
|
|
|
|
return values[i + j * width]
|
2015-10-06 00:11:56 +03:00
|
|
|
|
}
|
2015-10-06 00:18:35 +03:00
|
|
|
|
|
|
|
|
|
|
2015-10-06 00:18:40 +03:00
|
|
|
|
// MARK: Functor
|
|
|
|
|
|
2015-10-06 20:00:07 +03:00
|
|
|
|
public func map<Other>(transform: A -> Other) -> Matrix<Other> {
|
2015-10-06 00:18:40 +03:00
|
|
|
|
return Matrix<Other>(width: width, height: height, values: values.map { $0.map(transform) })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-10-06 00:18:35 +03:00
|
|
|
|
// MARK: Implementation details
|
|
|
|
|
|
|
|
|
|
private init(width: Int, height: Int, values: [Memo<A>]) {
|
|
|
|
|
self.width = width
|
|
|
|
|
self.height = height
|
|
|
|
|
self.values = values
|
|
|
|
|
}
|
2015-10-06 00:11:56 +03:00
|
|
|
|
}
|
2015-10-06 21:15:21 +03:00
|
|
|
|
|
2015-10-06 21:17:14 +03:00
|
|
|
|
/// Constructs a row-major ordering of values produced with `forEach`.
|
2015-11-05 23:45:19 +03:00
|
|
|
|
private func constructRowMajor<A, I: ForwardIndexType>(across: Range<I>, down: Range<I>, @noescape forEach: (I, I) -> A) -> [A] {
|
2015-10-06 21:15:21 +03:00
|
|
|
|
var values: [A] = []
|
2015-11-05 23:45:19 +03:00
|
|
|
|
values.reserveCapacity(Int(across.count.toIntMax()) * Int(down.count.toIntMax()))
|
|
|
|
|
for j in across {
|
|
|
|
|
for i in down {
|
2015-10-06 21:15:21 +03:00
|
|
|
|
values.append(forEach(i, j))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return values
|
|
|
|
|
}
|
2015-10-13 07:51:43 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import Memo
|