Swift: How to multiply array by array (Math: vector by vector)

大城市里の小女人 提交于 2019-11-27 15:33:00

"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.

dfri

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])
 }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!