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?
"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(*)
Single Instruction Multiple Data
If your vectors have exactly 4 components you can use the superfast simd
(Single Instruction Multiple Data) instructions provided by iOS.
It uses the CPU to perform parallel computations.
Given 2 vectors of 4 components of Int32
import simd
let a = int4(1, 2, 3, 4)
let b = int4(2, 3, 4, 5)
you can multiply each component
let res = a &* b // int4(2, 6, 12, 20)
As noted by Martin R , array of float(s)
or of double(s)
are provided as well by the simd
module.
Accelerate framework
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
.
With Swift 5, you can use one of the following ways in order to solve you problem.
#1. Using SIMD vector types
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)
#2. Using a custom type that conforms to Numeric
and ExpressibleByArrayLiteral
protocols
You 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)
let A = [1,2,3,4]
let B = [2,3,4,5]
var C = [Int]()
A.enumerated().forEach{ index, value in
return C.append(value * B[index])
}