diff --git a/Sources/Surge/General Arithmetic/Arithmetic.swift b/Sources/Surge/Arithmetic/Arithmetic.swift similarity index 57% rename from Sources/Surge/General Arithmetic/Arithmetic.swift rename to Sources/Surge/Arithmetic/Arithmetic.swift index 70ac70dd..460a091b 100644 --- a/Sources/Surge/General Arithmetic/Arithmetic.swift +++ b/Sources/Surge/Arithmetic/Arithmetic.swift @@ -22,42 +22,16 @@ import Accelerate // MARK: - Addition -public func add(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - precondition(lhs.count == rhs.count, "Collections must have the same size") - var results = [Float](rhs) - lhs.withUnsafeMemory { lhsMemory in - results.withUnsafeMutableBufferPointer { bufferPointer in - cblas_saxpy(numericCast(lhsMemory.count), 1.0, lhsMemory.pointer, numericCast(lhsMemory.stride), bufferPointer.baseAddress, 1) - } - } - return results -} - -public func add(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - precondition(lhs.count == rhs.count, "Collections must have the same size") - var results = [Double](rhs) - lhs.withUnsafeMemory { lhsMemory in - results.withUnsafeMutableBufferPointer { bufferPointer in - cblas_daxpy(numericCast(lhsMemory.count), 1.0, lhsMemory.pointer, numericCast(lhsMemory.stride), bufferPointer.baseAddress, 1) - } - } - return results -} - -public func .+ (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - return add(lhs, rhs) -} - -public func .+ (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - return add(lhs, rhs) -} - public func add(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { - return add(lhs, [Float](repeating: rhs, count: numericCast(lhs.count))) + var results = Array(lhs) + addInPlace(&results, rhs) + return results } public func add(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { - return add(lhs, [Double](repeating: rhs, count: numericCast(lhs.count))) + var results = Array(lhs) + addInPlace(&results, rhs) + return results } public func + (lhs: L, rhs: Float) -> [Float] where L.Element == Float { @@ -70,116 +44,132 @@ public func + (lhs: L, rhs: Double) -> [Double] where // MARK: - Addition: In Place -func addInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { +func addInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { + var scalar = rhs + lhs.withUnsafeMutableMemory { lm in - rhs.withUnsafeMemory { rm in - vDSP_vadd(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } + vDSP_vsadd(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -func addInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { +func addInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { + var scalar = rhs + lhs.withUnsafeMutableMemory { lm in - rhs.withUnsafeMemory { rm in - vDSP_vaddD(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } + vDSP_vsaddD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -public func .+= (lhs: inout L, rhs: R) where L.Element == Float, R.Element == Float { +public func +=(lhs: inout L, rhs: Float) where L.Element == Float { return addInPlace(&lhs, rhs) } -public func .+= (lhs: inout L, rhs: R) where L.Element == Double, R.Element == Double { +public func +=(lhs: inout L, rhs: Double) where L.Element == Double { return addInPlace(&lhs, rhs) } -func addInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsadd(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +// MARK: - Element-wise Addition + +public func add(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + return muladd(lhs, rhs, 1.0) } -func addInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsaddD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +public func add(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + return muladd(lhs, rhs, 1.0) } -public func +=(lhs: inout L, rhs: Float) where L.Element == Float { +public func .+ (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + return add(lhs, rhs) +} + +public func .+ (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + return add(lhs, rhs) +} + +// MARK: - Element-wise Addition: In Place + +func addInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { + muladdInPlace(&lhs, rhs, 1.0) +} + +func addInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { + muladdInPlace(&lhs, rhs, 1.0) +} + +public func .+= (lhs: inout L, rhs: R) where L.Element == Float, R.Element == Float { return addInPlace(&lhs, rhs) } -public func +=(lhs: inout L, rhs: Double) where L.Element == Double { +public func .+= (lhs: inout L, rhs: R) where L.Element == Double, R.Element == Double { return addInPlace(&lhs, rhs) } // MARK: - Subtraction -public func sub(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - precondition(lhs.count == rhs.count, "Collections must have the same size") - var results = [Float](rhs) - lhs.withUnsafeMemory { lhsMemory in - results.withUnsafeMutableBufferPointer { bufferPointer in - catlas_saxpby(numericCast(lhsMemory.count), 1.0, lhsMemory.pointer, numericCast(lhsMemory.stride), -1, bufferPointer.baseAddress, 1) - } - } +public func sub(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { + var results = Array(lhs) + subInPlace(&results, rhs) return results } -public func sub(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - precondition(lhs.count == rhs.count, "Collections must have the same size") - var results = [Double](rhs) - lhs.withUnsafeMemory { lhsMemory in - results.withUnsafeMutableBufferPointer { bufferPointer in - catlas_daxpby(numericCast(lhsMemory.count), 1.0, lhsMemory.pointer, numericCast(lhsMemory.stride), -1, bufferPointer.baseAddress, 1) - } - } +public func sub(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { + var results = Array(lhs) + subInPlace(&results, rhs) return results } -public func .- (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { +public func - (lhs: L, rhs: Float) -> [Float] where L.Element == Float { return sub(lhs, rhs) } -public func .- (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { +public func - (lhs: L, rhs: Double) -> [Double] where L.Element == Double { return sub(lhs, rhs) } -public func sub(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { - return sub(lhs, [Float](repeating: rhs, count: numericCast(lhs.count))) +// MARK: - Subtraction: In Place + +func subInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { + addInPlace(&lhs, -rhs) } -public func sub(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { - return sub(lhs, [Double](repeating: rhs, count: numericCast(lhs.count))) +func subInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { + addInPlace(&lhs, -rhs) } -public func - (lhs: L, rhs: Float) -> [Float] where L.Element == Float { +public func -=(lhs: inout L, rhs: Float) where L.Element == Float { + return subInPlace(&lhs, rhs) +} + +public func -=(lhs: inout L, rhs: Double) where L.Element == Double { + return subInPlace(&lhs, rhs) +} + +// MARK: - Element-wise Subtraction + +public func sub(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + return muladd(lhs, rhs, -1.0) +} + +public func sub(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + return muladd(lhs, rhs, -1.0) +} + +public func .- (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { return sub(lhs, rhs) } -public func - (lhs: L, rhs: Double) -> [Double] where L.Element == Double { +public func .- (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { return sub(lhs, rhs) } -// MARK: - Subtraction: In Place +// MARK: - Element-wise Subtraction: In Place func subInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { - lhs.withUnsafeMutableMemory { lm in - rhs.withUnsafeMemory { rm in - vDSP_vsub(rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } - } + muladdInPlace(&lhs, rhs, -1.0) } func subInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { - lhs.withUnsafeMutableMemory { lm in - rhs.withUnsafeMemory { rm in - vDSP_vsubD(rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } - } + muladdInPlace(&lhs, rhs, -1.0) } public func .-= (lhs: inout L, rhs: R) where L.Element == Float, R.Element == Float { @@ -190,79 +180,112 @@ public func .-= (lh return subInPlace(&lhs, rhs) } -func subInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { +// MARK: - Multiply Addition + +func muladd(_ lhs: L, _ rhs: R, _ alpha: Float) -> [Float] where L.Element == Float, R.Element == Float { + var results = Array(lhs) + muladdInPlace(&results, rhs, alpha) + return results +} + +func muladd(_ lhs: L, _ rhs: R, _ alpha: Double) -> [Double] where L.Element == Double, R.Element == Double { + var results = Array(lhs) + muladdInPlace(&results, rhs, alpha) + return results +} + +// MARK: - Multiply Addition: In Place + +func muladdInPlace(_ lhs: inout L, _ rhs: R, _ alpha: Float) where L.Element == Float, R.Element == Float { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in - var scalar = -rhs - vDSP_vsadd(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + rhs.withUnsafeMemory { rm in + cblas_saxpy(numericCast(lm.count), alpha, rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride)) + } } } -func subInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { +func muladdInPlace(_ lhs: inout L, _ rhs: R, _ alpha: Double) where L.Element == Double, R.Element == Double { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in - var scalar = -rhs - vDSP_vsaddD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + rhs.withUnsafeMemory { rm in + cblas_daxpy(numericCast(lm.count), alpha, rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride)) + } } } -public func -=(lhs: inout L, rhs: Float) where L.Element == Float { - return subInPlace(&lhs, rhs) +// MARK: - Multiplication + +public func mul(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { + var results = Array(lhs) + mulInPlace(&results, rhs) + return results } -public func -=(lhs: inout L, rhs: Double) where L.Element == Double { - return subInPlace(&lhs, rhs) +public func mul(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { + var results = Array(lhs) + mulInPlace(&results, rhs) + return results } -// MARK: - Multiplication +public func * (lhs: L, rhs: Float) -> [Float] where L.Element == Float { + return mul(lhs, rhs) +} -public func mul(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - var results = [Float](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vmul(lhsMemory.pointer, numericCast(lhsMemory.stride), rhsMemory.pointer, numericCast(rhsMemory.stride), bufferPointer.baseAddress!, 1, numericCast(lhsMemory.count)) - } - return results +public func * (lhs: L, rhs: Double) -> [Double] where L.Element == Double { + return mul(lhs, rhs) +} + +// MARK: - Multiplication: In Place + +func mulInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { + var scalar = rhs + lhs.withUnsafeMutableMemory { lm in + vDSP_vsmul(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -public func mul(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - var results = [Double](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vmulD(lhsMemory.pointer, numericCast(lhsMemory.stride), rhsMemory.pointer, numericCast(rhsMemory.stride), bufferPointer.baseAddress!, 1, numericCast(lhsMemory.count)) - } - return results +func mulInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { + var scalar = rhs + lhs.withUnsafeMutableMemory { lm in + vDSP_vsmulD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -public func .* (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - return mul(lhs, rhs) +public func *=(lhs: inout L, rhs: Float) where L.Element == Float { + return mulInPlace(&lhs, rhs) } -public func .* (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - return mul(lhs, rhs) +public func *=(lhs: inout L, rhs: Double) where L.Element == Double { + return mulInPlace(&lhs, rhs) } -public func mul(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { - return mul(lhs, [Float](repeating: rhs, count: numericCast(lhs.count))) +// MARK: - Element-wise Multiplication + +public func mul(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + var results = Array(lhs) + mulInPlace(&results, rhs) + return results } -public func mul(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { - return mul(lhs, [Double](repeating: rhs, count: numericCast(lhs.count))) +public func mul(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + var results = Array(lhs) + mulInPlace(&results, rhs) + return results } -public func * (lhs: L, rhs: Float) -> [Float] where L.Element == Float { +public func .* (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { return mul(lhs, rhs) } -public func * (lhs: L, rhs: Double) -> [Double] where L.Element == Double { +public func .* (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { return mul(lhs, rhs) } -// MARK: - Multiplication: In Place +// MARK: - Element-wise Multiplication: In Place func mulInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in rhs.withUnsafeMemory { rm in vDSP_vmul(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) @@ -271,6 +294,7 @@ func mulInPlace(_ l } func mulInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in rhs.withUnsafeMemory { rm in vDSP_vmulD(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) @@ -286,92 +310,90 @@ public func .*= (lh return mulInPlace(&lhs, rhs) } -func mulInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsmul(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +// MARK: - Division + +public func div(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { + var results = Array(lhs) + divInPlace(&results, rhs) + return results } -func mulInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsmulD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +public func div(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { + var results = Array(lhs) + divInPlace(&results, rhs) + return results } -public func *=(lhs: inout L, rhs: Float) where L.Element == Float { - return mulInPlace(&lhs, rhs) +public func / (lhs: L, rhs: Float) -> [Float] where L.Element == Float { + return div(lhs, rhs) } -public func *=(lhs: inout L, rhs: Double) where L.Element == Double { - return mulInPlace(&lhs, rhs) +public func / (lhs: L, rhs: Double) -> [Double] where L.Element == Double { + return div(lhs, rhs) } -// MARK: - Division +// MARK: - Division: In Place -/// Elemen-wise vector division. -public func div(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - var results = [Float](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vdiv(rhsMemory.pointer, numericCast(rhsMemory.stride), lhsMemory.pointer, numericCast(lhsMemory.stride), bufferPointer.baseAddress!, 1, numericCast(lhsMemory.count)) - } - return results +func divInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { + lhs.withUnsafeMutableMemory { lm in + var scalar = rhs + vDSP_vsdiv(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -/// Elemen-wise vector division. -public func div(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - var results = [Double](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vdivD(rhsMemory.pointer, numericCast(rhsMemory.stride), lhsMemory.pointer, numericCast(lhsMemory.stride), bufferPointer.baseAddress!, 1, numericCast(lhsMemory.count)) - } - return results +func divInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { + lhs.withUnsafeMutableMemory { lm in + var scalar = rhs + vDSP_vsdivD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } -public func ./ (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - return div(lhs, rhs) +public func /=(lhs: inout L, rhs: Float) where L.Element == Float { + return divInPlace(&lhs, rhs) } -public func ./ (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - return div(lhs, rhs) +public func /=(lhs: inout L, rhs: Double) where L.Element == Double { + return divInPlace(&lhs, rhs) } -public func div(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { - return div(lhs, [Float](repeating: rhs, count: numericCast(lhs.count))) +// MARK: - Element-wise Division + +public func div(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + var results = Array(lhs) + divInPlace(&results, rhs) + return results } -public func div(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { - return div(lhs, [Double](repeating: rhs, count: numericCast(lhs.count))) +public func div(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + var results = Array(lhs) + divInPlace(&results, rhs) + return results } -public func / (lhs: L, rhs: Float) -> [Float] where L.Element == Float { +public func ./ (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { return div(lhs, rhs) } -public func / (lhs: L, rhs: Double) -> [Double] where L.Element == Double { +public func ./ (lhs: L, rhs: R) -> [Double] where L.Element == Double, R.Element == Double { return div(lhs, rhs) } -// MARK: - Division: In Place +// MARK: - Element-wise Division: In Place func divInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in rhs.withUnsafeMemory { rm in - vDSP_vdiv(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + vDSP_vdiv(rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } } func divInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { + precondition(lhs.count == rhs.count, "Collections must have the same size") lhs.withUnsafeMutableMemory { lm in rhs.withUnsafeMemory { rm in - vDSP_vdivD(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + vDSP_vdivD(rm.pointer, numericCast(rm.stride), lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) } } } @@ -384,58 +406,74 @@ public func ./= (lh return divInPlace(&lhs, rhs) } -func divInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsdiv(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +// MARK: - Modulo + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func mod(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { + var results = Array(lhs) + modInPlace(&results, rhs) + return results } -func divInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { - lhs.withUnsafeMutableMemory { lm in - var scalar = rhs - vDSP_vsdivD(lm.pointer, numericCast(lm.stride), &scalar, lm.pointer, numericCast(lm.stride), numericCast(lm.count)) - } +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func mod(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { + var results = Array(lhs) + modInPlace(&results, rhs) + return results } -public func /=(lhs: inout L, rhs: Float) where L.Element == Float { - return divInPlace(&lhs, rhs) +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func % (lhs: L, rhs: Float) -> [Float] where L.Element == Float { + return mod(lhs, rhs) } -public func /=(lhs: inout L, rhs: Double) where L.Element == Double { - return divInPlace(&lhs, rhs) +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func % (lhs: L, rhs: Double) -> [Double] where L.Element == Double { + return mod(lhs, rhs) } -// MARK: - Modulo +// MARK: - Modulo: In Place + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +/// - Warning: does not support memory stride (assumes stride is 1). +func modInPlace(_ lhs: inout L, _ rhs: Float) where L.Element == Float { + let rhs = Array(repeating: rhs, count: lhs.count) + modInPlace(&lhs, rhs) +} + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +/// - Warning: does not support memory stride (assumes stride is 1). +func modInPlace(_ lhs: inout L, _ rhs: Double) where L.Element == Double { + let rhs = Array(repeating: rhs, count: lhs.count) + modInPlace(&lhs, rhs) +} + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +/// - Warning: does not support memory stride (assumes stride is 1). +public func .%= (lhs: inout L, rhs: Float) where L.Element == Float { + return modInPlace(&lhs, rhs) +} + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +/// - Warning: does not support memory stride (assumes stride is 1). +public func .%= (lhs: inout L, rhs: Double) where L.Element == Double { + return modInPlace(&lhs, rhs) +} + +// MARK: - Element-wise Modulo -/// Elemen-wise modulo. -/// /// - Warning: does not support memory stride (assumes stride is 1). public func mod(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") - var results = [Float](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvfmodf(bufferPointer.baseAddress!, lhsMemory.pointer, rhsMemory.pointer, [numericCast(lhsMemory.count)]) - } - return results - } + var results = Array(lhs) + modInPlace(&results, rhs) + return results } -/// Elemen-wise modulo. -/// /// - Warning: does not support memory stride (assumes stride is 1). public func mod(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { - precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") - var results = [Double](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvfmod(bufferPointer.baseAddress!, lhsMemory.pointer, rhsMemory.pointer, [numericCast(lhsMemory.count)]) - } - return results - } + var results = Array(lhs) + modInPlace(&results, rhs) + return results } public func .% (lhs: L, rhs: R) -> [Float] where L.Element == Float, R.Element == Float { @@ -446,51 +484,75 @@ public func .% (lhs: L, rh return mod(lhs, rhs) } -public func mod(_ lhs: L, _ rhs: Float) -> [Float] where L.Element == Float { - return mod(lhs, [Float](repeating: rhs, count: numericCast(lhs.count))) +// MARK: - Element-wise Modulo: In Place + +/// - Warning: does not support memory stride (assumes stride is 1). +public func modInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { + precondition(lhs.count == rhs.count, "Collections must have the same size") + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + withUnsafeMemory(rhs) { rm in + vvfmodf(lm.pointer, lm.pointer, rm.pointer, &elementCount) + } + } } -public func mod(_ lhs: L, _ rhs: Double) -> [Double] where L.Element == Double { - return mod(lhs, [Double](repeating: rhs, count: numericCast(lhs.count))) +/// - Warning: does not support memory stride (assumes stride is 1). +public func modInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { + precondition(lhs.count == rhs.count, "Collections must have the same size") + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + withUnsafeMemory(rhs) { rm in + vvfmod(lm.pointer, lm.pointer, rm.pointer, &elementCount) + } + } } -public func % (lhs: L, rhs: Float) -> [Float] where L.Element == Float { - return mod(lhs, rhs) +public func .%= (lhs: inout L, rhs: R) where L.Element == Float, R.Element == Float { + return modInPlace(&lhs, rhs) } -public func % (lhs: L, rhs: Double) -> [Double] where L.Element == Double { - return mod(lhs, rhs) +public func .%= (lhs: inout L, rhs: R) where L.Element == Double, R.Element == Double { + return modInPlace(&lhs, rhs) } // MARK: - Remainder -/// Elemen-wise remainder. -/// /// - Warning: does not support memory stride (assumes stride is 1). public func remainder(_ lhs: L, _ rhs: R) -> [Float] where L.Element == Float, R.Element == Float { + var results = Array(lhs) + remainderInPlace(&results, rhs) + return results +} + +/// - Warning: does not support memory stride (assumes stride is 1). +public func remainder(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { + var results = Array(lhs) + remainderInPlace(&results, rhs) + return results +} + +// MARK: - Remainder: In Place + +/// - Warning: does not support memory stride (assumes stride is 1). +func remainderInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Float, R.Element == Float { precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") - var results = [Float](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvremainderf(bufferPointer.baseAddress!, lhsMemory.pointer, rhsMemory.pointer, [numericCast(lhsMemory.count)]) + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + withUnsafeMemory(rhs) { rm in + vvremainderf(lm.pointer, lm.pointer, rm.pointer, &elementCount) } - return results } } -/// Elemen-wise remainder. -/// /// - Warning: does not support memory stride (assumes stride is 1). -public func remainder(_ lhs: L, _ rhs: R) -> [Double] where L.Element == Double, R.Element == Double { +func remainderInPlace(_ lhs: inout L, _ rhs: R) where L.Element == Double, R.Element == Double { precondition(lhs.count == rhs.count, "Collections must have the same size") - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") - var results = [Double](repeating: 0.0, count: numericCast(lhsMemory.count)) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvremainder(bufferPointer.baseAddress!, lhsMemory.pointer, rhsMemory.pointer, [numericCast(lhsMemory.count)]) + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + withUnsafeMemory(rhs) { rm in + vvremainder(lm.pointer, lm.pointer, rm.pointer, &elementCount) } - return results } } @@ -498,33 +560,35 @@ public func remainder(_ lh /// - Warning: does not support memory stride (assumes stride is 1). public func exp(_ lhs: X) -> [Float] where X.Element == Float { - return lhs.withUnsafeMemory { lhsMemory in - precondition(lhsMemory.stride == 1, "\(#function) does not support strided memory access") - - var lhsCount = Int32(lhs.count) - - var results = [Float](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvexpf(bufferPointer.baseAddress!, lhsMemory.pointer, &lhsCount) - } - - return results - } + var results = Array(lhs) + expInPlace(&results) + return results } /// - Warning: does not support memory stride (assumes stride is 1). public func exp(_ lhs: X) -> [Double] where X.Element == Double { - return lhs.withUnsafeMemory { lhsMemory in - precondition(lhsMemory.stride == 1, "\(#function) does not support strided memory access") + var results = Array(lhs) + expInPlace(&results) + return results +} - var lhsCount = Int32(lhs.count) +// MARK: - Exponential: In Place - var results = [Double](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvexp(bufferPointer.baseAddress!, lhsMemory.pointer, &lhsCount) - } +/// - Warning: does not support memory stride (assumes stride is 1). +func expInPlace(_ lhs: inout X) where X.Element == Float { + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + vvexpf(lm.pointer, lm.pointer, &elementCount) + } +} - return results +/// - Warning: does not support memory stride (assumes stride is 1). +func expInPlace(_ lhs: inout X) where X.Element == Double { + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + vvexp(lm.pointer, lm.pointer, &elementCount) } } @@ -532,33 +596,35 @@ public func exp(_ lhs: X) -> [Double] where X.Element /// - Warning: does not support memory stride (assumes stride is 1). public func exp2(_ lhs: X) -> [Float] where X.Element == Float { - return lhs.withUnsafeMemory { lhsMemory in - precondition(lhsMemory.stride == 1, "\(#function) does not support strided memory access") - - var lhsCount = Int32(lhs.count) - - var results = [Float](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvexp2f(bufferPointer.baseAddress!, lhsMemory.pointer, &lhsCount) - } - - return results - } + var results = Array(lhs) + exp2InPlace(&results) + return results } /// - Warning: does not support memory stride (assumes stride is 1). public func exp2(_ lhs: X) -> [Double] where X.Element == Double { - return lhs.withUnsafeMemory { lhsMemory in - precondition(lhsMemory.stride == 1, "\(#function) does not support strided memory access") + var results = Array(lhs) + exp2InPlace(&results) + return results +} - var lhsCount = Int32(lhs.count) +// MARK: - Square Exponentiation: In Place - var results = [Double](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { bufferPointer in - vvexp2(bufferPointer.baseAddress!, lhsMemory.pointer, &lhsCount) - } +/// - Warning: does not support memory stride (assumes stride is 1). +func exp2InPlace(_ lhs: inout X) where X.Element == Float { + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + vvexp2f(lm.pointer, lm.pointer, &elementCount) + } +} - return results +/// - Warning: does not support memory stride (assumes stride is 1). +func exp2InPlace(_ lhs: inout X) where X.Element == Double { + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + vvexp2(lm.pointer, lm.pointer, &elementCount) } } @@ -566,44 +632,98 @@ public func exp2(_ lhs: X) -> [Double] where X.Elemen /// - Warning: does not support memory stride (assumes stride is 1). public func pow(_ lhs: X, _ rhs: Y) -> [Float] where X.Element == Float, Y.Element == Float { - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") + var results = Array(lhs) + powInPlace(&results, rhs) + return results +} - var lhsCount = Int32(lhs.count) +/// - Warning: does not support memory stride (assumes stride is 1). +public func pow(_ lhs: X, _ rhs: Y) -> [Double] where X.Element == Double, Y.Element == Double { + var results = Array(lhs) + powInPlace(&results, rhs) + return results +} - var results = [Float](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { pointer in - vvpowf(pointer.baseAddress!, rhsMemory.pointer, lhsMemory.pointer, &lhsCount) - } +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func pow(_ lhs: X, _ rhs: Float) -> [Float] where X.Element == Float { + var results = Array(lhs) + powInPlace(&results, rhs) + return results +} + +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +public func pow(_ lhs: X, _ rhs: Double) -> [Double] where X.Element == Double { + var results = Array(lhs) + powInPlace(&results, rhs) + return results +} - return results +// MARK: - Power: In Place + +/// - Warning: does not support memory stride (assumes stride is 1). +func powInPlace(_ lhs: inout X, _ rhs: Y) where X.Element == Float, Y.Element == Float { + precondition(lhs.count == rhs.count, "Collections must have the same size") + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + withUnsafeMemory(rhs) { rm in + precondition(rm.stride == 1, "\(#function) does not support strided memory access") + vvpowf(lm.pointer, rm.pointer, lm.pointer, &elementCount) + } } } /// - Warning: does not support memory stride (assumes stride is 1). -public func pow(_ lhs: X, _ rhs: Y) -> [Double] where X.Element == Double, Y.Element == Double { - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.stride == 1 && rhsMemory.stride == 1, "\(#function) does not support strided memory access") +func powInPlace(_ lhs: inout X, _ rhs: Y) where X.Element == Double, Y.Element == Double { + precondition(lhs.count == rhs.count, "Collections must have the same size") + var elementCount: Int32 = numericCast(lhs.count) + withUnsafeMutableMemory(&lhs) { lm in + precondition(lm.stride == 1, "\(#function) does not support strided memory access") + withUnsafeMemory(rhs) { rm in + precondition(rm.stride == 1, "\(#function) does not support strided memory access") + vvpow(lm.pointer, rm.pointer, lm.pointer, &elementCount) + } + } +} - var lhsCount = Int32(lhs.count) +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +func powInPlace(_ lhs: inout X, _ rhs: Float) where X.Element == Float { + let rhs = Array(repeating: rhs, count: lhs.count) + return powInPlace(&lhs, rhs) +} - var results = [Double](repeating: 0.0, count: lhs.count) - results.withUnsafeMutableBufferPointer { pointer in - vvpow(pointer.baseAddress!, rhsMemory.pointer, lhsMemory.pointer, &lhsCount) - } +/// - Warning: Allocates a temporary array from `rhs` via `Array(repeating: rhs, count: lhs.count)`. +func powInPlace(_ lhs: inout X, _ rhs: Double) where X.Element == Double { + let rhs = Array(repeating: rhs, count: lhs.count) + return powInPlace(&lhs, rhs) +} - return results - } +//// MARK: - Square + +public func sq(_ lhs: L) -> [Float] where L.Element == Float { + var results = Array(lhs) + sqInPlace(&results) + return results } -public func pow(_ lhs: X, _ rhs: Float) -> [Float] where X.Element == Float { - let rhs = [Float](repeating: rhs, count: lhs.count) - return pow(lhs, rhs) +public func sq(_ lhs: L) -> [Double] where L.Element == Double { + var results = Array(lhs) + sqInPlace(&results) + return results } -public func pow(_ lhs: X, _ rhs: Double) -> [Double] where X.Element == Double { - let rhs = [Double](repeating: rhs, count: lhs.count) - return pow(lhs, rhs) +// MARK: - Square: In Place + +func sqInPlace(_ lhs: inout L) where L.Element == Float { + withUnsafeMutableMemory(&lhs) { lm in + vDSP_vsq(lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + } +} + +public func sqInPlace(_ lhs: inout L) where L.Element == Double { + withUnsafeMutableMemory(&lhs) { lm in + vDSP_vsqD(lm.pointer, numericCast(lm.stride), lm.pointer, numericCast(lm.stride), numericCast(lm.count)) + } } // MARK: - Square Root @@ -612,8 +732,8 @@ public func pow(_ lhs: X, _ rhs: Double) -> [Double] /// /// - Warning: does not support memory stride (assumes stride is 1). public func sqrt(_ lhs: C) -> [Float] where C.Element == Float { - var results = [Float](repeating: 0.0, count: numericCast(lhs.count)) - sqrt(lhs, into: &results) + var results = Array(lhs) + sqrtInPlace(&results) return results } @@ -621,11 +741,11 @@ public func sqrt(_ lhs: C) -> [Float] where C.Element /// /// - Warning: does not support memory stride (assumes stride is 1). public func sqrt(_ lhs: MI, into results: inout MO) where MI.Element == Float, MO.Element == Float { - return lhs.withUnsafeMemory { lhsMemory in + return lhs.withUnsafeMemory { lm in results.withUnsafeMutableMemory { rm in - precondition(lhsMemory.stride == 1 && rm.stride == 1, "sqrt doesn't support step values other than 1") - precondition(rm.count >= lhsMemory.count, "`results` doesnt have enough capacity to store the results") - vvsqrtf(rm.pointer, lhsMemory.pointer, [numericCast(lhsMemory.count)]) + precondition(lm.stride == 1 && rm.stride == 1, "sqrt doesn't support step values other than 1") + precondition(rm.count >= lm.count, "`results` doesnt have enough capacity to store the results") + vvsqrtf(rm.pointer, lm.pointer, [numericCast(lm.count)]) } } } @@ -634,8 +754,8 @@ public func sqrt( /// /// - Warning: does not support memory stride (assumes stride is 1). public func sqrt(_ lhs: C) -> [Double] where C.Element == Double { - var results = [Double](repeating: 0.0, count: numericCast(lhs.count)) - sqrt(lhs, into: &results) + var results = Array(lhs) + sqrtInPlace(&results) return results } @@ -643,39 +763,59 @@ public func sqrt(_ lhs: C) -> [Double] where C.Elemen /// /// - Warning: does not support memory stride (assumes stride is 1). public func sqrt(_ lhs: MI, into results: inout MO) where MI.Element == Double, MO.Element == Double { - return lhs.withUnsafeMemory { lhsMemory in + return lhs.withUnsafeMemory { lm in results.withUnsafeMutableMemory { rm in - precondition(lhsMemory.stride == 1 && rm.stride == 1, "sqrt doesn't support step values other than 1") - precondition(rm.count >= lhsMemory.count, "`results` doesnt have enough capacity to store the results") - vvsqrt(rm.pointer, lhsMemory.pointer, [numericCast(lhsMemory.count)]) + precondition(lm.stride == 1 && rm.stride == 1, "sqrt doesn't support step values other than 1") + precondition(rm.count >= lm.count, "`results` doesnt have enough capacity to store the results") + vvsqrt(rm.pointer, lm.pointer, [numericCast(lm.count)]) } } } +// MARK: - Square Root: In Place + +/// Elemen-wise square root. +/// +/// - Warning: does not support memory stride (assumes stride is 1). +func sqrtInPlace(_ lhs: inout C) where C.Element == Float { + var elementCount: Int32 = numericCast(lhs.count) + lhs.withUnsafeMutableMemory { lm in + precondition(lm.stride == 1, "\(#function) doesn't support step values other than 1") + vvsqrtf(lm.pointer, lm.pointer, &elementCount) + } +} + +/// Elemen-wise square root. +/// +/// - Warning: does not support memory stride (assumes stride is 1). +func sqrtInPlace(_ lhs: inout C) where C.Element == Double { + var elementCount: Int32 = numericCast(lhs.count) + lhs.withUnsafeMutableMemory { lm in + precondition(lm.stride == 1, "\(#function) doesn't support step values other than 1") + vvsqrt(lm.pointer, lm.pointer, &elementCount) + } +} + // MARK: - Dot Product public func dot(_ lhs: L, _ rhs: R) -> Float where L.Element == Float, R.Element == Float { - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.count == rhsMemory.count, "Vectors must have equal count") - + return withUnsafeMemory(lhs, rhs) { lm, rm in + precondition(lm.count == rm.count, "Vectors must have equal count") var result: Float = 0.0 withUnsafeMutablePointer(to: &result) { pointer in - vDSP_dotpr(lhsMemory.pointer, numericCast(lhsMemory.stride), rhsMemory.pointer, numericCast(rhsMemory.stride), pointer, numericCast(lhsMemory.count)) + vDSP_dotpr(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), pointer, numericCast(lm.count)) } - return result } } public func dot(_ lhs: L, _ rhs: R) -> Double where L.Element == Double, R.Element == Double { - return withUnsafeMemory(lhs, rhs) { lhsMemory, rhsMemory in - precondition(lhsMemory.count == rhsMemory.count, "Vectors must have equal count") - + return withUnsafeMemory(lhs, rhs) { lm, rm in + precondition(lm.count == rm.count, "Vectors must have equal count") var result: Double = 0.0 withUnsafeMutablePointer(to: &result) { pointer in - vDSP_dotprD(lhsMemory.pointer, numericCast(lhsMemory.stride), rhsMemory.pointer, numericCast(rhsMemory.stride), pointer, numericCast(lhsMemory.count)) + vDSP_dotprD(lm.pointer, numericCast(lm.stride), rm.pointer, numericCast(rm.stride), pointer, numericCast(lm.count)) } - return result } } @@ -704,20 +844,14 @@ public func dist(_ lhs: L, public func distSq(_ lhs: L, _ rhs: R) -> Float where L.Element == Float, R.Element == Float { precondition(lhs.count == rhs.count, "Vectors must have equal count") - let sub = lhs .- rhs - var squared = [Float](repeating: 0.0, count: numericCast(lhs.count)) - squared.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vsq(sub, 1, bufferPointer.baseAddress!, 1, numericCast(lhs.count)) - } - return sum(squared) + var partialDistancesSquared = lhs .- rhs + sqInPlace(&partialDistancesSquared) + return sum(partialDistancesSquared) } public func distSq(_ lhs: L, _ rhs: R) -> Double where L.Element == Double, R.Element == Double { precondition(lhs.count == rhs.count, "Vectors must have equal count") - let sub = lhs .- rhs - var squared = [Double](repeating: 0.0, count: numericCast(lhs.count)) - squared.withUnsafeMutableBufferPointer { bufferPointer in - vDSP_vsqD(sub, 1, bufferPointer.baseAddress!, 1, numericCast(lhs.count)) - } - return sum(squared) + var partialDistancesSquared = lhs .- rhs + sqInPlace(&partialDistancesSquared) + return sum(partialDistancesSquared) } diff --git a/Sources/Surge/Linear Algebra/Matrix.swift b/Sources/Surge/Linear Algebra/Matrix.swift index aa3bc612..a4fd0bb8 100644 --- a/Sources/Surge/Linear Algebra/Matrix.swift +++ b/Sources/Surge/Linear Algebra/Matrix.swift @@ -267,25 +267,19 @@ public func == (lhs: Matrix, rhs: Matrix) -> Bool { // MARK: - Addition public func add(_ lhs: Matrix, _ rhs: Matrix) -> Matrix { - precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with addition") + var result = lhs - var results = rhs - results.grid.withUnsafeMutableBufferPointer { pointer in - cblas_saxpy(Int32(lhs.grid.count), 1.0, lhs.grid, 1, pointer.baseAddress!, 1) - } + result += rhs - return results + return result } public func add(_ lhs: Matrix, _ rhs: Matrix) -> Matrix { - precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with addition") + var result = lhs - var results = rhs - results.grid.withUnsafeMutableBufferPointer { pointer in - cblas_daxpy(Int32(lhs.grid.count), 1.0, lhs.grid, 1, pointer.baseAddress!, 1) - } + result += rhs - return results + return result } public func + (lhs: Matrix, rhs: Matrix) -> Matrix { @@ -296,28 +290,38 @@ public func + (lhs: Matrix, rhs: Matrix) -> Matrix { return add(lhs, rhs) } +// MARK: - Addition: In Place + +func addInPlace(_ lhs: inout Matrix, _ rhs: Matrix) { + muladdInPlace(&lhs, rhs, 1.0) +} + +func addInPlace(_ lhs: inout Matrix, _ rhs: Matrix) { + muladdInPlace(&lhs, rhs, 1.0) +} + +public func += (lhs: inout Matrix, rhs: Matrix) { + return addInPlace(&lhs, rhs) +} + +public func += (lhs: inout Matrix, rhs: Matrix) { + return addInPlace(&lhs, rhs) +} + // MARK: - Subtraction public func sub(_ lhs: Matrix, _ rhs: Matrix) -> Matrix { - precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with subtraction") - - var results = rhs - results.grid.withUnsafeMutableBufferPointer { pointer in - catlas_saxpby(Int32(lhs.grid.count), 1.0, lhs.grid, 1, -1, pointer.baseAddress!, 1) - } + var result = lhs + result -= rhs - return results + return result } public func sub(_ lhs: Matrix, _ rhs: Matrix) -> Matrix { - precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with subtraction") + var result = lhs + result -= rhs - var results = rhs - results.grid.withUnsafeMutableBufferPointer { pointer in - catlas_daxpby(Int32(lhs.grid.count), 1.0, lhs.grid, 1, -1, pointer.baseAddress!, 1) - } - - return results + return result } public func - (lhs: Matrix, rhs: Matrix) -> Matrix { @@ -328,6 +332,70 @@ public func - (lhs: Matrix, rhs: Matrix) -> Matrix { return sub(lhs, rhs) } +// MARK: - Subtraction: In Place + +func subInPlace(_ lhs: inout Matrix, _ rhs: Matrix) { + muladdInPlace(&lhs, rhs, -1.0) +} + +func subInPlace(_ lhs: inout Matrix, _ rhs: Matrix) { + muladdInPlace(&lhs, rhs, -1.0) +} + +public func -= (lhs: inout Matrix, rhs: Matrix) { + return subInPlace(&lhs, rhs) +} + +public func -= (lhs: inout Matrix, rhs: Matrix) { + return subInPlace(&lhs, rhs) +} + +// MARK: - Multiply Addition + +func muladd(_ lhs: Matrix, _ rhs: Matrix, _ alpha: Float) -> Matrix { + var result = lhs + + muladdInPlace(&result, rhs, alpha) + + return result +} + +func muladd(_ lhs: Matrix, _ rhs: Matrix, _ alpha: Double) -> Matrix { + var result = lhs + + muladdInPlace(&result, rhs, alpha) + + return result +} + +// MARK: - Multiply Addition: In Place + +func muladdInPlace(_ lhs: inout Matrix, _ rhs: Matrix, _ alpha: Float) { + precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with addition") + + let gridSize = Int32(lhs.grid.count) + let stride: Int32 = 1 + + lhs.grid.withUnsafeMutableBufferPointer { lhsPointer in + rhs.grid.withUnsafeBufferPointer { rhsPointer in + cblas_saxpy(gridSize, alpha, rhsPointer.baseAddress!, stride, lhsPointer.baseAddress!, stride) + } + } +} + +func muladdInPlace(_ lhs: inout Matrix, _ rhs: Matrix, _ alpha: Double) { + precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrix dimensions not compatible with addition") + + let gridSize = Int32(lhs.grid.count) + let stride: Int32 = 1 + + lhs.grid.withUnsafeMutableBufferPointer { lhsPointer in + rhs.grid.withUnsafeBufferPointer { rhsPointer in + cblas_daxpy(gridSize, alpha, rhsPointer.baseAddress!, stride, lhsPointer.baseAddress!, stride) + } + } +} + // MARK: - Multiplication public func mul(_ lhs: Matrix, _ rhs: Matrix) -> Matrix { diff --git a/Surge.xcodeproj/project.pbxproj b/Surge.xcodeproj/project.pbxproj index b752853d..198d8888 100644 --- a/Surge.xcodeproj/project.pbxproj +++ b/Surge.xcodeproj/project.pbxproj @@ -255,7 +255,7 @@ 615394541F762B58002A4AD2 /* Surge.h */, CAEC79CB2319336500516E10 /* Auxiliary Functions */, CAEC79C92319333E00516E10 /* Digital Signal Processing */, - CAEC79CA2319335100516E10 /* General Arithmetic */, + CAEC79CA2319335100516E10 /* Arithmetic */, CAEC79CD2319338F00516E10 /* Linear Algebra */, CAEC79D02319343100516E10 /* Logarithm */, CAEC79CC2319337700516E10 /* Statistics */, @@ -305,12 +305,12 @@ path = "Digital Signal Processing"; sourceTree = ""; }; - CAEC79CA2319335100516E10 /* General Arithmetic */ = { + CAEC79CA2319335100516E10 /* Arithmetic */ = { isa = PBXGroup; children = ( 6153944B1F762B58002A4AD2 /* Arithmetic.swift */, ); - path = "General Arithmetic"; + path = Arithmetic; sourceTree = ""; }; CAEC79CB2319336500516E10 /* Auxiliary Functions */ = { diff --git a/Tests/SurgeTests/ArithmeticTests.swift b/Tests/SurgeTests/ArithmeticTests.swift index f15b288c..ad9fd4ff 100644 --- a/Tests/SurgeTests/ArithmeticTests.swift +++ b/Tests/SurgeTests/ArithmeticTests.swift @@ -529,6 +529,38 @@ class ArithmeticTests: XCTestCase { XCTAssertEqual(actual, expected, accuracy: 1e-8) } + // MARK: - Square + + func test_sq_array_float() { + typealias Scalar = Float + + let lhs: [Scalar] = (1...n).map { Scalar($0) / Scalar(n) } + + var actual: [Scalar] = [] + measure { + actual = Surge.sq(lhs) + } + + let expected = lhs.map { pow($0, 2.0) } + + XCTAssertEqual(actual, expected, accuracy: 1e-5) + } + + func test_sq_array_double() { + typealias Scalar = Double + + let lhs: [Scalar] = (1...n).map { Scalar($0) / Scalar(n) } + + var actual: [Scalar] = [] + measure { + actual = Surge.sq(lhs) + } + + let expected = lhs.map { pow($0, 2.0) } + + XCTAssertEqual(actual, expected, accuracy: 1e-8) + } + // MARK: - Square Root func test_sqrt_array_array_float() { @@ -678,7 +710,9 @@ class ArithmeticTests: XCTestCase { actual = distSq(lhs, rhs) } - let expected: Scalar = Swift.zip(lhs, rhs).map({ $0 - $1 }).map({ $0 * $0 }).reduce(0.0, +) + let partialDistances: [Scalar] = Swift.zip(lhs, rhs).map { $0 - $1 } + let partialDistancesSquared: [Scalar] = partialDistances.map { $0 * $0 } + let expected: Scalar = partialDistancesSquared.reduce(0.0, +) XCTAssertEqual(actual, expected, accuracy: 1e-6) } @@ -694,7 +728,9 @@ class ArithmeticTests: XCTestCase { actual = distSq(lhs, rhs) } - let expected: Scalar = Swift.zip(lhs, rhs).map({ $0 - $1 }).map({ $0 * $0 }).reduce(0.0, +) + let partialDistances: [Scalar] = Swift.zip(lhs, rhs).map { $0 - $1 } + let partialDistancesSquared: [Scalar] = partialDistances.map { $0 * $0 } + let expected: Scalar = partialDistancesSquared.reduce(0.0, +) XCTAssertEqual(actual, expected, accuracy: 1e-6) } diff --git a/Tests/SurgeTests/MatrixTests.swift b/Tests/SurgeTests/MatrixTests.swift index 66f87306..f016efa7 100644 --- a/Tests/SurgeTests/MatrixTests.swift +++ b/Tests/SurgeTests/MatrixTests.swift @@ -116,8 +116,10 @@ class MatrixTests: XCTestCase { } func test_init_identity() { - let actual: Matrix = Matrix.identity(size: 3) - let expected: Matrix = [ + typealias Scalar = Double + + let actual: Matrix = Matrix.identity(size: 3) + let expected: Matrix = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], @@ -126,23 +128,25 @@ class MatrixTests: XCTestCase { } func test_init_eye() { - let actual_2x3: Matrix = Matrix.eye(rows: 2, columns: 3) - let expected_2x3: Matrix = [ + typealias Scalar = Double + + let actual_2x3: Matrix = Matrix.eye(rows: 2, columns: 3) + let expected_2x3: Matrix = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], ] XCTAssertEqual(actual_2x3, expected_2x3) - let actual_3x2: Matrix = Matrix.eye(rows: 3, columns: 2) - let expected_3x2: Matrix = [ + let actual_3x2: Matrix = Matrix.eye(rows: 3, columns: 2) + let expected_3x2: Matrix = [ [1.0, 0.0], [0.0, 1.0], [0.0, 0.0], ] XCTAssertEqual(actual_3x2, expected_3x2) - let actual_3x3: Matrix = Matrix.eye(rows: 3, columns: 3) - let expected_3x3: Matrix = [ + let actual_3x3: Matrix = Matrix.eye(rows: 3, columns: 3) + let expected_3x3: Matrix = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], @@ -151,23 +155,25 @@ class MatrixTests: XCTestCase { } func test_init_diagonal_repeatedValue() { - let actual_2x3: Matrix = Matrix.diagonal(rows: 2, columns: 3, repeatedValue: 42.0) - let expected_2x3: Matrix = [ + typealias Scalar = Double + + let actual_2x3: Matrix = Matrix.diagonal(rows: 2, columns: 3, repeatedValue: 42.0) + let expected_2x3: Matrix = [ [42.0, 0.0, 0.0], [0.0, 42.0, 0.0], ] XCTAssertEqual(actual_2x3, expected_2x3) - let actual_3x2: Matrix = Matrix.diagonal(rows: 3, columns: 2, repeatedValue: 42.0) - let expected_3x2: Matrix = [ + let actual_3x2: Matrix = Matrix.diagonal(rows: 3, columns: 2, repeatedValue: 42.0) + let expected_3x2: Matrix = [ [42.0, 0.0], [0.0, 42.0], [0.0, 0.0], ] XCTAssertEqual(actual_3x2, expected_3x2) - let actual_3x3: Matrix = Matrix.diagonal(rows: 3, columns: 3, repeatedValue: 42.0) - let expected_3x3: Matrix = [ + let actual_3x3: Matrix = Matrix.diagonal(rows: 3, columns: 3, repeatedValue: 42.0) + let expected_3x3: Matrix = [ [42.0, 0.0, 0.0], [0.0, 42.0, 0.0], [0.0, 0.0, 42.0], @@ -176,23 +182,25 @@ class MatrixTests: XCTestCase { } func test_init_diagonal_scalars() { - let actual_2x3: Matrix = Matrix.diagonal(rows: 2, columns: 3, scalars: [1, 2]) - let expected_2x3: Matrix = [ + typealias Scalar = Double + + let actual_2x3: Matrix = Matrix.diagonal(rows: 2, columns: 3, scalars: [1, 2]) + let expected_2x3: Matrix = [ [1.0, 0.0, 0.0], [0.0, 2.0, 0.0], ] XCTAssertEqual(actual_2x3, expected_2x3) - let actual_3x2: Matrix = Matrix.diagonal(rows: 3, columns: 2, scalars: [1, 2]) - let expected_3x2: Matrix = [ + let actual_3x2: Matrix = Matrix.diagonal(rows: 3, columns: 2, scalars: [1, 2]) + let expected_3x2: Matrix = [ [1.0, 0.0], [0.0, 2.0], [0.0, 0.0], ] XCTAssertEqual(actual_3x2, expected_3x2) - let actual_3x3: Matrix = Matrix.diagonal(rows: 3, columns: 3, scalars: [1, 2, 3]) - let expected_3x3: Matrix = [ + let actual_3x3: Matrix = Matrix.diagonal(rows: 3, columns: 3, scalars: [1, 2, 3]) + let expected_3x3: Matrix = [ [1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 3.0], @@ -280,7 +288,7 @@ class MatrixTests: XCTestCase { ] let actual = matrix + matrix - let expected: Matrix = [ + let expected: Matrix = [ [2, 4, 6, 8], [10, 12, 14, 16], [18, 20, 22, 24], @@ -308,6 +316,50 @@ class MatrixTests: XCTestCase { XCTAssertEqual(actual, expected) } + // MARK: - Addition: In Place + + func test_add_in_place_matrix_matrix_float() { + typealias Scalar = Float + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + var actual = matrix + actual += matrix + + let expected: Matrix = [ + [2, 4, 6, 8], + [10, 12, 14, 16], + [18, 20, 22, 24], + ] + + XCTAssertEqual(actual, expected) + } + + func test_add_in_place_matrix_matrix_double() { + typealias Scalar = Double + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + var actual = matrix + actual += matrix + + let expected: Matrix = [ + [2, 4, 6, 8], + [10, 12, 14, 16], + [18, 20, 22, 24], + ] + + XCTAssertEqual(actual, expected) + } + // MARK: - Subtraction func test_sub_matrix_matrix_float() { @@ -320,7 +372,7 @@ class MatrixTests: XCTestCase { ] let actual = matrix - matrix - let expected: Matrix = [ + let expected: Matrix = [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], @@ -348,6 +400,132 @@ class MatrixTests: XCTestCase { XCTAssertEqual(actual, expected) } + // MARK: - Subtraction: In Place + + func test_sub_in_place_matrix_matrix_float() { + typealias Scalar = Float + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + var actual = matrix + actual -= matrix + + let expected: Matrix = [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ] + + XCTAssertEqual(actual, expected) + } + + func test_sub_in_place_matrix_matrix_double() { + typealias Scalar = Double + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + var actual = matrix + actual -= matrix + + let expected: Matrix = [ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0], + ] + + XCTAssertEqual(actual, expected) + } + + // MARK: - Multiply Addition + + func test_muladd_matrix_matrix_scalar_float() { + typealias Scalar = Float + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + let actual = matrix + matrix + let expected: Matrix = [ + [2, 4, 6, 8], + [10, 12, 14, 16], + [18, 20, 22, 24], + ] + + XCTAssertEqual(actual, expected) + } + + func test_muladd_matrix_matrix_scalar_double() { + typealias Scalar = Double + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + let actual = muladd(matrix, matrix, 2.0) + let expected: Matrix = [ + [3, 6, 9, 12], + [15, 18, 21, 24], + [27, 30, 33, 36], + ] + + XCTAssertEqual(actual, expected) + } + + // MARK: - Multiply Addition: In Place + + func test_muladd_in_place_matrix_matrix_scalar_float() { + typealias Scalar = Float + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + let actual = muladd(matrix, matrix, 2.0) + let expected: Matrix = [ + [3, 6, 9, 12], + [15, 18, 21, 24], + [27, 30, 33, 36], + ] + + XCTAssertEqual(actual, expected) + } + + func test_muladd_in_place_matrix_matrix_scalar_double() { + typealias Scalar = Double + + let matrix: Matrix = [ + [1, 2, 3, 4], + [5, 6, 7, 8], + [9, 10, 11, 12], + ] + + var actual = matrix + actual += matrix + + let expected: Matrix = [ + [2, 4, 6, 8], + [10, 12, 14, 16], + [18, 20, 22, 24], + ] + + XCTAssertEqual(actual, expected) + } + // MARK: - Multiplication func test_mul_matrix_matrix_float() { @@ -829,7 +1007,9 @@ class MatrixTests: XCTestCase { } func test_eigen_decomposition_trivial() throws { - try eigen_decomposition_trivial_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in + typealias Scalar = Double + + try eigen_decomposition_trivial_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in try eigenDecompose(m) } try eigen_decomposition_trivial_generic(defaultAccuracy: 1e-8) { (m: Matrix) throws -> MatrixEigenDecompositionResult in @@ -856,7 +1036,9 @@ class MatrixTests: XCTestCase { } func test_eigen_decomposition_complex_results_numpy_example() throws { - try eigen_decomposition_complex_results_numpy_example_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in + typealias Scalar = Double + + try eigen_decomposition_complex_results_numpy_example_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in try eigenDecompose(m) } try eigen_decomposition_complex_results_numpy_example_generic(defaultAccuracy: 1e-8) { (m: Matrix) throws -> MatrixEigenDecompositionResult in @@ -905,7 +1087,9 @@ class MatrixTests: XCTestCase { } func test_eigen_decomposition_complex_results_dgeev_example() throws { - try eigen_decomposition_complex_results_dgeev_example_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in + typealias Scalar = Double + + try eigen_decomposition_complex_results_dgeev_example_generic(defaultAccuracy: 1e-11) { (m: Matrix) throws -> MatrixEigenDecompositionResult in try eigenDecompose(m) } try eigen_decomposition_complex_results_dgeev_example_generic(defaultAccuracy: 1e-8) { (m: Matrix) throws -> MatrixEigenDecompositionResult in @@ -914,7 +1098,9 @@ class MatrixTests: XCTestCase { } func test_eigen_decompose_throws_when_not_square() throws { - let matrix = Matrix([ + typealias Scalar = Double + + let matrix = Matrix([ [1, 0, 0], [0, 2, 0], ])