arrays - una - Cómo multiplicar dos matrices por elementos
suma elementos de una matriz (5)
Acelerar el marco
Para el tema de la multiplicación de vectores, otra alternativa (además
del
simd
cubierto por la respuesta de @ appzYourLife
) está haciendo uso del
marco Acelerar
.
En este caso, específicamente los
métodos
vDSP_vmul
y
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)
Por ejemplo, este último utilizado para la multiplicación elemento por elemento de dos vectores de valores
Double
:
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]
}
Tenga en cuenta que usar Accelerate no es tan fácil de usar y seguro como los métodos alternativos, ya que los argumentos vectoriales para
vDSP_vmulD
se capturan como punteros inseguros (
UnsafePointer<Double>
), y es nuestra responsabilidad asegurarnos de que los vectores de entrada sean de la misma longitud , así como que el vector resultante se asigne correctamente antes de la multiplicación del vector por
vDSP_vmulD
.
Necesito multiplicar una matriz por otra matriz en cuanto a elementos, al igual que el producto Hadamard de vectores en matemáticas. Por ejemplo:
A = [1,2,3,4]
B = [2,3,4,5]
C = A*B = [2,6,12,20]
Ni siquiera puedo descifrar el código, he intentado hacerlo elemento por elemento, pero esto me parece una solución demasiado desordenada, ¿alguna idea?
Instrucción única Datos múltiples
Si sus vectores tienen exactamente 4 componentes, puede usar las
instrucciones
simd
(
Single Instruction Multiple Data
) proporcionadas por iOS.
Utiliza la CPU para realizar cálculos paralelos.
Dados 2 vectores de 4 componentes de
Int32
import simd
let a = int4(1, 2, 3, 4)
let b = int4(2, 3, 4, 5)
puedes multiplicar cada componente
let res = a &* b // int4(2, 6, 12, 20)
Como señaló Martin R , el módulo
simd
también proporciona una matriz defloat(s)
o dedouble(s)
.
Al "comprimir" las dos matrices se obtiene una secuencia de tuplas
(a_i, b_i)
que luego se pueden multiplicar por elementos:
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]
(Si las matrices tienen una longitud diferente,
zip
ignora silenciosamente los elementos adicionales de la matriz más larga).
Como @appzYourLife dijo correctamente, también puede pasar el operador de multiplicación directamente como un argumento para
map
lugar de una expresión de cierre:
let C = zip(A, B).map(*)
Con Swift 5, puede usar una de las siguientes formas para resolver su problema.
# 1 Usando tipos de vectores SIMD
El siguiente código de muestra de Playground muestra una multiplicación por elementos usando
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)
Tenga en cuenta que el protocolo
SIMD
ajusta a
ExpressibleByArrayLiteral
.
Por lo tanto, puede inicializar su vector usando una matriz 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
Usar un tipo personalizado que se ajuste a los protocolos
Numeric
y
ExpressibleByArrayLiteral
Puede crear su propio tipo personalizado que se ajuste a
Numeric
y
ExpressibleByArrayLiteral
.
El siguiente código de muestra de Playground muestra cómo implementarlo y usarlo:
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]
}
}
Uso:
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])
}