Skip to content

Commit 372d27a

Browse files
committed
New abstractions in NDimensionalType: size, init, deriving. Testing factorization of element-wise op (subtracting for vectors & matrix). Added new setter.
1 parent c757e96 commit 372d27a

File tree

5 files changed

+103
-41
lines changed

5 files changed

+103
-41
lines changed

NDimensionalType.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,26 @@ public protocol NDimensionalType: CustomStringConvertible {
1313
associatedtype NativeIndexRange: Sequence where NativeIndexRange.Element == NativeIndex
1414
var dimension: Int { get }
1515
var shape: [Int] { get } // size is dimension
16+
var size: NativeIndex { get }
17+
18+
init(repeating value: Element, size: NativeIndex)
1619

1720
// we don't define as vararg arrays, we let that up to the actual type to opt-out from array use (performance).
1821
subscript(index: [Int]) -> Element { get set }
1922
subscript(index: NativeIndex) -> Element { get set }
2023
var indices: NativeIndexRange { get }
24+
25+
// internal func deriving() -> Self
2126
}
2227

2328
extension NDimensionalType {
29+
// quickie to allocate result with same size as self.
30+
internal func _deriving(_ prep: (Self) -> ()) -> Self {
31+
let result = Self(repeating: .none, size: self.size)
32+
prep(result)
33+
return result
34+
}
35+
2436
private func recursiveDescription(index: [Int]) -> String {
2537
var description = ""
2638
let dimi = index.count

NMatrix.swift

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
2828

2929
public var rows: Int { return slice.row.rcount }
3030
public var columns: Int { return slice.column.rcount }
31-
public var size: (rows: Int, columns: Int) { return (rows, columns) }
31+
// public var width: Int { return columns }
32+
// public var height: Int { return rows }
33+
public var size: NativeIndex { return (rows, columns) }
3234
public var indices: NQuadraticIndexRange { return NQuadraticIndexRange(rows: rows, columns: columns) }
3335
public var compact: Bool { return slice.compact }
3436

@@ -50,7 +52,7 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
5052
let storage = Storage(allocatedCount: rows * columns, value: value)
5153
self.init(storage: storage, slice: .default(rows: rows, columns: columns))
5254
}
53-
public init(repeating value: Element = .none, size: (Int, Int)) {
55+
public init(repeating value: Element = .none, size: NativeIndex) {
5456
self.init(repeating: value, rows: size.0, columns: size.1)
5557
}
5658

@@ -68,6 +70,12 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
6870
}
6971
}
7072
}
73+
// init from row-major values (values.count = rows x columns)
74+
public init(_ values: [Element], rows: Int, columns: Int) {
75+
precondition(values.count == rows * columns)
76+
self.init(rows: rows, columns: columns)
77+
self.set(from: values)
78+
}
7179

7280
public func copy() -> NMatrix {
7381
let result = NMatrix(rows: rows, columns: columns)
@@ -104,14 +112,6 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
104112
}
105113
}
106114

107-
// quickie to allocate result with same size as self.
108-
internal func _deriving(_ prep: (Matrix) -> ()) -> Matrix {
109-
let result = Matrix(rows: rows, columns: columns)
110-
prep(result)
111-
return result
112-
}
113-
114-
115115
// Get row/column as vector
116116
private func vector(row: Int) -> Vector {
117117
let rslice = NResolvedSlice(start: slice.position(row, 0), count: columns, step: slice.column.rstep)
@@ -180,7 +180,7 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
180180
public subscript(indexes: NMatrixi) -> Vector {
181181
get {
182182
precondition(indexes.columns == 2)
183-
let result = Vector(size: indexes.size.rows)
183+
let result = Vector(size: indexes.size.row)
184184
for index in indexes.indices.row {
185185
let selfindex = (indexes[index, 0], indexes[index, 1])
186186
assert(selfindex.0 >= 0 && selfindex.0 < self.rows)
@@ -191,7 +191,7 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
191191
}
192192
nonmutating set {
193193
precondition(indexes.columns == 2)
194-
precondition(newValue.size == indexes.size.rows)
194+
precondition(newValue.size == indexes.size.row)
195195
for index in indexes.indices.row {
196196
let selfindex = (indexes[index, 0], indexes[index, 1])
197197
assert(selfindex.0 >= 0 && selfindex.0 < self.rows)
@@ -215,6 +215,7 @@ public struct NMatrix<Element: NValue> : NStorageAccessible {
215215
// TODO: These Vector / Matrix funcs are very similar. Could probably push that into NDimensionalType.
216216
extension NMatrix {
217217
// Access
218+
// Note: set API does not expose data range as NMatrix slicing is used for that
218219
public func set(from: Matrix) {
219220
for (pos, rpos) in zip(slice, from.slice) {
220221
storage[pos] = from.storage[rpos]
@@ -231,6 +232,12 @@ extension NMatrix {
231232
if mask[i] { self[i] = value }
232233
}
233234
}
235+
public func set(from rowMajorValues: [Element]) {
236+
precondition(rowMajorValues.count == rows * columns)
237+
for (pos, rpos) in zip(slice, rowMajorValues.indices) {
238+
storage[pos] = rowMajorValues[rpos]
239+
}
240+
}
234241
}
235242

236243
extension NMatrix where Element: SignedNumeric, Element.Magnitude == Element {

NOps.swift

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,25 @@ public enum ConvolutionDomain {
2323
// case full // M+K-1
2424
}
2525

26+
// MARK: - Generic Dimensional Type Ops (apply to Vector, Matrix, Tensor)
27+
// Typically element-wise operations that can be implemented in terms to linearized access (any dimensions).
28+
extension Numerics where Element: AccelerateFloatingPoint {
29+
public static func subtract<DT: NStorageAccessible>(_ a: DT, _ b: DT, _ result: DT) where DT.Element == Element {
30+
precondition(a.shape == b.shape && a.shape == result.shape)
31+
32+
withLinearizedAccesses(a, b, result) { aacc, bacc, racc in
33+
Element.mx_vsub(aacc.base, aacc.stride, bacc.base, bacc.stride, racc.base, racc.stride, numericCast(racc.count))
34+
}
35+
}
36+
public static func subtract<DT: NStorageAccessible>(_ a: DT, _ b: DT) -> DT where DT.Element == Element { return a._deriving { subtract(a, b, $0) } }
37+
}
38+
39+
2640
// MARK: - Vector Ops
2741
extension Numerics where Element: AccelerateFloatingPoint {
2842
/// Creation of vectors
29-
public static func zeros(count: Int) -> Vector { return Vector(repeating: 0.0, count: count) }
30-
public static func ones(count: Int) -> Vector { return NVector(repeating: 1.0, count: count) }
43+
public static func zeros(count: Int) -> Vector { return Vector(repeating: 0.0, size: count) }
44+
public static func ones(count: Int) -> Vector { return NVector(repeating: 1.0, size: count) }
3145
public static func linspace(start: Element, stop: Element, count: Int, output: Vector) {
3246
precondition(count == output.size)
3347
precondition(count >= 2)
@@ -102,8 +116,8 @@ extension Numerics where Element: AccelerateFloatingPoint {
102116
let afterstart = before+input.size
103117

104118
output[before ..< afterstart] = input
105-
output[0 ..< before] = NVector(repeating: input.first!, count: before)
106-
output[afterstart ..< output.size] = NVector(repeating: input.last!, count: after)
119+
output[0 ..< before] = NVector(repeating: input.first!, size: before)
120+
output[afterstart ..< output.size] = NVector(repeating: input.last!, size: after)
107121
}
108122

109123
// Arithmetic
@@ -141,13 +155,13 @@ extension Numerics where Element: AccelerateFloatingPoint {
141155
}
142156
public static func multiply(_ a: Vector, _ b: Vector) -> Vector { return a._deriving { multiply(a, b, $0) } }
143157

144-
public static func subtract(_ a: Vector, _ b: Vector, _ result: Vector) {
145-
precondition(a.shape == b.shape && a.shape == result.shape)
146-
withStorageAccess(a, b, result) { aacc, bacc, racc in
147-
Element.mx_vsub(aacc.base, aacc.stride, bacc.base, bacc.stride, racc.base, racc.stride, numericCast(racc.count))
148-
}
149-
}
150-
public static func subtract(_ a: Vector, _ b: Vector) -> Vector { return a._deriving { subtract(a, b, $0) } }
158+
// public static func subtract(_ a: Vector, _ b: Vector, _ result: Vector) {
159+
// precondition(a.shape == b.shape && a.shape == result.shape)
160+
// withStorageAccess(a, b, result) { aacc, bacc, racc in
161+
// Element.mx_vsub(aacc.base, aacc.stride, bacc.base, bacc.stride, racc.base, racc.stride, numericCast(racc.count))
162+
// }
163+
// }
164+
// public static func subtract(_ a: Vector, _ b: Vector) -> Vector { return a._deriving { subtract(a, b, $0) } }
151165
public static func add(_ a: Vector, _ b: Vector, _ result: Vector) {
152166
precondition(a.shape == b.shape && a.shape == result.shape)
153167
withStorageAccess(a, b, result) { aacc, bacc, racc in
@@ -270,6 +284,13 @@ extension NVector where Element: AccelerateFloatingPoint {
270284
extension Numerics where Element: AccelerateFloatingPoint {
271285
public static func zeros(rows: Int, columns: Int) -> Matrix { return Matrix(repeating: 0.0, rows: rows, columns: columns) }
272286
public static func ones(rows: Int, columns: Int) -> Matrix { return Matrix(repeating: 1.0, rows: rows, columns: columns) }
287+
// public static func add(_ a: Vector, _ b: Vector, _ result: Vector) {
288+
// precondition(a.shape == b.shape && a.shape == result.shape)
289+
// withStorageAccess(a, b, result) { aacc, bacc, racc in
290+
// Element.mx_vadd(aacc.base, aacc.stride, bacc.base, bacc.stride, racc.base, racc.stride, numericCast(racc.count))
291+
// }
292+
// }
293+
// public static func add(_ a: Vector, _ b: Vector) -> Vector { return a._deriving { add(a, b, $0) } }
273294

274295
public static func multiply(_ a: Matrix, _ b: Element, _ result: Matrix) {
275296
precondition(a.shape == result.shape)
@@ -526,6 +547,10 @@ extension NMatrix where Element: AccelerateFloatingPoint {
526547
return result
527548
}
528549

550+
// Matrix/Matric
551+
public static func -(lhs: Matrix, rhs: Matrix) -> Matrix { return Numerics.subtract(lhs, rhs) }
552+
// public static func +(lhs: Matrix, rhs: Matrix) -> Matrix { return Numerics.add(lhs, rhs) }
553+
529554
// Matrix/Vector
530555
public static func *(lhs: Matrix, rhs: Matrix) -> Matrix { return Numerics.multiply(lhs, rhs) }
531556
public static func *(lhs: Matrix, rhs: Vector) -> Vector { return Numerics.multiply(lhs, rhs) }

NStorage.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,17 @@ extension NStorage {
132132
public let base: UnsafeMutablePointer<Element>
133133

134134
// navigate relatively to the first element.
135+
136+
// stride: storage distance (elements) between elements in successive row/column
135137
public let stride: (row: Int, column: Int)
138+
// count: number of rows / columns
136139
public let count: (row: Int, column: Int)
137140
// Note: QuadraticAccess's slice always starts at 0 (unlike Matrix's)
138141
public var slice: NResolvedQuadraticSlice { return NResolvedQuadraticSlice(row: NResolvedSlice(start: 0, count: count.row, step: stride.row), column: NResolvedSlice(start: 0, count: count.column, step: stride.column)) }
139142

143+
// shortcut for APIs that need this
144+
public var rowBytes: Int { return stride.row * MemoryLayout<Element>.stride }
145+
140146
public var compact: Bool { return stride.column == 1 && stride.row == count.column }
141147
// points to the first element of row or columns
142148
public func base(row: Int) -> UnsafeMutablePointer<Element> { return base + row * stride.row }
@@ -201,6 +207,7 @@ extension Numerics {
201207
}
202208
}
203209
public static func withLinearizedAccesses<T: NStorageAccessible>(_ a: T, _ b: T, _ access: (Storage.LinearAccess, Storage.LinearAccess) -> Void) where T.Element == Element {
210+
precondition(a.shape == b.shape)
204211
a._withStorageAccess { aacc in
205212
b._withStorageAccess { bacc in
206213
let coalesce = aacc.compact && bacc.compact
@@ -210,6 +217,19 @@ extension Numerics {
210217
}
211218
}
212219
}
220+
public static func withLinearizedAccesses<T: NStorageAccessible>(_ a: T, _ b: T, _ c: T, _ access: (Storage.LinearAccess, Storage.LinearAccess, Storage.LinearAccess) -> Void) where T.Element == Element {
221+
precondition(a.shape == b.shape && a.shape == c.shape)
222+
a._withStorageAccess { aacc in
223+
b._withStorageAccess { bacc in
224+
c._withStorageAccess { cacc in
225+
let coalesce = aacc.compact && bacc.compact && cacc.compact
226+
for (alin, (blin, clin)) in zip(aacc.linearized(coalesce: coalesce), zip(bacc.linearized(coalesce: coalesce), cacc.linearized(coalesce: coalesce))) {
227+
access(alin, blin, clin)
228+
}
229+
}
230+
}
231+
}
232+
}
213233
// MARK: - Storage/Value Stride
214234
internal static func withAddresses<T: NStorageAccessible>(_ a: T, _ block: (_ pointer: UnsafeMutablePointer<Element>) -> Void) where T.Element == Element {
215235
a._withStorageAccess { aacc in

NVector.swift

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,23 +32,23 @@ public struct NVector<Element: NValue> : NStorageAccessible {
3232
//layout = l
3333
slice = sl
3434
}
35-
public init(size: Int) {
36-
let storage = Storage(allocatedCount: size)
37-
self.init(storage: storage, slice: .default(count: size))
38-
}
35+
// public init(size: Int) {
36+
// let storage = Storage(allocatedCount: size)
37+
// self.init(storage: storage, slice: .default(count: size))
38+
// }
3939
public init(storage mem: Storage, count: Int) {
4040
let slice = NResolvedSlice(start: 0, count: count, step: 1)
4141
self.init(storage: mem, slice: slice)
4242
}
43-
public init(_ elements: [Element]) {
44-
self.init(size: elements.count)
45-
43+
public init(_ values: [Element]) {
44+
self.init(size: values.count)
4645
storage.withUnsafeAccess { access in
47-
_ = UnsafeMutableBufferPointer(start: access.base, count: self.size).initialize(from: elements)
46+
_ = UnsafeMutableBufferPointer(start: access.base, count: self.size).initialize(from: values)
4847
}
4948
}
50-
public init(repeating value: Element, count: Int) {
51-
self.init(size: count)
49+
public init(repeating value: Element = .none, size: Int) {
50+
let storage = Storage(allocatedCount: size)
51+
self.init(storage: storage, slice: .default(count: size))
5252

5353
storage.withUnsafeAccess { access in
5454
_ = UnsafeMutableBufferPointer(start: access.base, count: self.size).initialize(repeating: value)
@@ -67,13 +67,6 @@ public struct NVector<Element: NValue> : NStorageAccessible {
6767
return result
6868
}
6969

70-
// quickie to allocate result with same size as self.
71-
internal func _deriving(_ prep: (Vector) -> ()) -> Vector {
72-
let result = Vector(size: self.size)
73-
prep(result)
74-
return result
75-
}
76-
7770
// MARK: - Slicing -
7871
public subscript(_ s: NSliceExpression) -> Vector {
7972
get { return Vector(storage: storage, slice: s.resolve(within: slice)) }
@@ -144,11 +137,16 @@ public struct NVector<Element: NValue> : NStorageAccessible {
144137
extension NVector {
145138
public func set(from: Vector) {
146139
precondition(from.slice.rcount == slice.rcount)
147-
148140
Numerics.withAddresses(from, self) { pfrom, pself in
149141
pself.pointee = pfrom.pointee
150142
}
151143
}
144+
public func set(from: [Element]) {
145+
precondition(from.count == size)
146+
for (i, j) in zip(self.indices, 0..<from.count) {
147+
self[i] = from[j]
148+
}
149+
}
152150
public func set(_ value: Element) {
153151
for i in self.indices {
154152
self[i] = value

0 commit comments

Comments
 (0)