I need to multiply an array by another array element-wise, just like the Hadamard product of vectors in math. For example:
A = [1,2,3,4]
B = [2,3,4,5]
C = A*B = [2,6,12,20]
I can't even figure out the code, I've tried doing so element by element but this seems too messy of a solution for me, any ideas?
For the topic of vector multiplication, another alternative (in addition to the neat simd
covered by @appzYourLife's answer) is making use of the Accelerate framework. In this case, specifically the vDSP methods vDSP_vmul
and vDSP_vmuld
,
func vDSP_vmul(UnsafePointer<Float>, vDSP_Stride, UnsafePointer<Float>, vDSP_Stride, UnsafeMutablePointer<Float>, vDSP_Stride, vDSP_Length) func vDSP_vmulD(UnsafePointer<Double>, vDSP_Stride, UnsafePointer<Double>, vDSP_Stride, UnsafeMutablePointer<Double>, vDSP_Stride, vDSP_Length)
E.g., the latter used for element-by-element multiplication of two vectors of Double
values:
import Accelerate
let a = [1.5, 2.5, 16.5, 7.5, 3.0]
let b = [3.0, 4.5, 0.25, 3.5, 6.25]
var result = [Double](repeating: 0.0, count: a.count)
if a.count == b.count {
vDSP_vmulD(a, 1, b, 1, &result, 1, vDSP_Length(a.count))
print(result) // [4.5, 11.25, 4.125, 26.25, 18.75]
}
Note that using Accelerate is not as user friendly and safe as the alternative methods, as the vector arguments to vDSP_vmulD
are captured as unsafe pointers (UnsafePointer<Double>
), and that it's our responsibility to make sure that the input vectors are of same length, as well as the result vector being properly allocated prior to the vector multiplication by vDSP_vmulD
.
"Zipping" the two arrays gives a sequence of tuples (a_i, b_i)
which can then be multiplied element-wise:
let A = [1,2,3,4]
let B = [2,3,4,5]
let C = zip(A, B).map { $0 * $1 }
print(C) // [2, 6, 12, 20]
(If the arrays have different length then zip
silently ignores the extra elements of the longer array.)
As @appzYourLife correctly said, you can also pass the multiplication
operator directly as an argument to map
instead of a closure expression:
let C = zip(A, B).map(*)
With Swift 5, you can use one of the following ways in order to solve you problem.
The following Playground sample code shows an element-wise multiplication using SIMD4
:
let vector1 = SIMD4(1, 2, 3, 4)
let vector2 = SIMD4(2, 3, 4, 5)
let vector3 = vector1 &* vector2
print(vector3) // prints: SIMD4<Int>(2, 6, 12, 20)
Note that SIMD
protocol conforms to ExpressibleByArrayLiteral
. Therefore, you can initialize your vector using an array literal:
var vector1: SIMD4 = [1, 2, 3, 4]
let vector2: SIMD4 = [2, 3, 4, 5]
vector1 &*= vector2
print(vector1) // prints: SIMD4<Int>(2, 6, 12, 20)
Numeric
and ExpressibleByArrayLiteral
protocolsYou can build your own custom type that conforms to Numeric
and ExpressibleByArrayLiteral
. The following Playground sample code shows how to implement and use it:
struct Vector {
let x, y: Int
init(_ x: Int, _ y: Int) {
self.x = x
self.y = y
}
}
extension Vector: AdditiveArithmetic {
static var zero: Vector {
return Vector(0, 0)
}
static func +(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
}
static func +=(lhs: inout Vector, rhs: Vector) {
lhs = lhs + rhs
}
static func -(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
}
static func -=(lhs: inout Vector, rhs: Vector) {
lhs = lhs - rhs
}
}
extension Vector: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
x = value
y = value
}
}
import Darwin
extension Vector: Numeric {
var magnitude: Int {
// Implement according to your needs
return Int(Darwin.sqrt(Double(x * x + y * y)))
}
init?<T>(exactly source: T) where T : BinaryInteger {
guard let source = source as? Int else {
return nil
}
x = source
y = source
}
static func *(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x * rhs.y, lhs.y * rhs.x)
}
static func *=(lhs: inout Vector, rhs: Vector) {
lhs = lhs * rhs
}
}
extension Vector: ExpressibleByArrayLiteral {
init(arrayLiteral elements: Int...) {
assert(elements.count == 2, "arrayLiteral should have exactly 2 elements")
self.x = elements[0]
self.y = elements[1]
}
}
Usage:
let vector1 = Vector(1, 2)
let vector2 = Vector(2, 3)
let vector3 = vector1 * vector2
print(vector3) // prints: Vector(x: 3, y: 4)
let vector1: Vector = [1, 2]
let vector2: Vector = [2, 3]
let vector3 = vector1 * vector2
print(vector3) // prints: Vector(x: 3, y: 4)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With