mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This brings the David Owens benchmark from http://owensd.io/2015/06/27/performance-xcode7-beta-2.html from parity with simd.h-based C to 3x faster. Before: RenderGradient ([UInt32].withUnsafeMutablePointer (SIMD)) │ 7.035851 │ 6.304739 │ 9.815832 │ 1.212 │ After: RenderGradient ([UInt32].withUnsafeMutablePointer (SIMD)) │ 2.318357 │ 2.223325 │ 2.697981 │ 0.1490 │ This also addresses rdar://problem/21574425, since Builtin.add_VecNxIntM isn't overflow-checked, and overflow checks really aren't wanted when working with vector types directly. Reapplying now that Nadav's fixed the ARM64 SelectionDAG issue this exposed before. Swift SVN r29922
786 lines
24 KiB
Swift
786 lines
24 KiB
Swift
//===----------------------------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
// simd.h overlays for Swift
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Swift
|
|
import Darwin
|
|
@exported import simd
|
|
|
|
% component = ['x','y','z','w']
|
|
% scalar_types = ['Float','Double','Int32']
|
|
% ctype = { 'Float':'float', 'Double':'double', 'Int32':'int' }
|
|
% llvm_type = { 'Float':'FPIEEE32', 'Double':'FPIEEE64', 'Int32':'Int32' }
|
|
% floating_types = ['Float','Double']
|
|
% cardinal = { 2:'two', 3:'three', 4:'four'}
|
|
% hash_scales = ['1', '3', '5', '11']
|
|
% one_minus_ulp = { 'Float':'0x1.fffffep-1', 'Double':'0x1.fffffffffffffp-1' }
|
|
|
|
% for type in scalar_types:
|
|
% for size in [2, 3, 4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% vectype = ctype[type] + str(size)
|
|
% llvm_vectype = "Vec" + str(size) + "x" + llvm_type[type]
|
|
% vecsize = (8 if type == 'Double' else 4)*(2 if size == 2 else 4)
|
|
% extractelement = "extractelement_" + llvm_vectype + "_Int32"
|
|
% insertelement = "insertelement_" + llvm_vectype + "_" + llvm_type[type] + "_Int32"
|
|
|
|
/// A vector of ${cardinal[size]} `${type}`. This corresponds to the C and
|
|
/// Obj-C type `vector_${vectype}` and the C++ type `simd::${vectype}`.
|
|
@_alignment(${vecsize})
|
|
public struct ${vectype} :
|
|
ArrayLiteralConvertible, CustomDebugStringConvertible {
|
|
|
|
public var _vector: Builtin.${llvm_vectype}
|
|
|
|
% for i in xrange(size):
|
|
public var ${component[i]} : ${type} {
|
|
@transparent
|
|
get {
|
|
let elt = Builtin.${extractelement}(_vector,
|
|
(${i} as Int32).value)
|
|
|
|
return ${type}(_bits: elt)
|
|
}
|
|
@transparent
|
|
set {
|
|
_vector = Builtin.${insertelement}(_vector,
|
|
newValue.value,
|
|
(${i} as Int32).value)
|
|
}
|
|
}
|
|
% end
|
|
|
|
/// Initialize to the zero vector.
|
|
@transparent
|
|
public init() { self.init(0) }
|
|
|
|
@transparent
|
|
public init(_bits: Builtin.${llvm_vectype}) {
|
|
_vector = _bits
|
|
}
|
|
|
|
/// Initialize a vector with the specified elements.
|
|
@transparent
|
|
public init(${', '.join(map(lambda c: '_ ' + c + ': ' + type, component[:size]))}) {
|
|
var v: Builtin.${llvm_vectype} = Builtin.zeroInitializer()
|
|
% for i in xrange(size):
|
|
v = Builtin.${insertelement}(v,
|
|
${component[i]}.value,
|
|
(${i} as Int32).value)
|
|
% end
|
|
_vector = v
|
|
}
|
|
|
|
/// Initialize a vector with the specified elements.
|
|
@transparent
|
|
public init(${', '.join(map(lambda c: c + ': ' + type, component[:size]))}) {
|
|
self.init(${', '.join(c for c in component[:size])})
|
|
}
|
|
|
|
/// Initialize to a vector with all elements equal to `scalar`.
|
|
@transparent
|
|
public init(_ scalar: ${type}) {
|
|
self.init(${', '.join(['scalar']*size)})
|
|
}
|
|
|
|
/// Initialize to a vector with elements taken from `array`.
|
|
///
|
|
/// - Precondition: `array` must have exactly ${cardinal[size]} elements.
|
|
public init(_ array: [${type}]) {
|
|
_precondition(array.count == ${size},
|
|
"${vectype} requires a ${cardinal[size]}-element array")
|
|
self.init(${', '.join(map(lambda i:
|
|
'array[' + str(i) + ']',
|
|
range(size)))})
|
|
}
|
|
|
|
/// Initialize using `arrayLiteral`.
|
|
///
|
|
/// - Precondition: the array literal must exactly ${cardinal[size]} elements.
|
|
public init(arrayLiteral elements: ${type}...) { self.init(elements) }
|
|
|
|
/// Access individual elements of the vector via subscript.
|
|
public subscript(index: Int) -> ${type} {
|
|
@transparent
|
|
get {
|
|
_precondition(index >= 0, "vector index out of range")
|
|
_precondition(index < ${size}, "vector index out of range")
|
|
let elt = Builtin.${extractelement}(_vector,
|
|
Int32(index).value)
|
|
return ${type}(_bits: elt)
|
|
}
|
|
@transparent
|
|
set(value) {
|
|
_precondition(index >= 0, "vector index out of range")
|
|
_precondition(index < ${size}, "vector index out of range")
|
|
_vector = Builtin.${insertelement}(_vector,
|
|
value.value,
|
|
Int32(index).value)
|
|
}
|
|
}
|
|
|
|
/// Debug string representation
|
|
public var debugDescription: String {
|
|
return "${vectype}(${', '.join(map(lambda c:
|
|
'\\(' + c + ')',
|
|
component[:size]))})"
|
|
}
|
|
|
|
/// Helper for matrix debug representations
|
|
internal var _descriptionAsArray: String {
|
|
get {
|
|
return "[${', '.join(map(lambda c:
|
|
'\\(' + c + ')',
|
|
component[:size]))}]"
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Vector sum of `lhs` and `rhs`.
|
|
@inline(__always)
|
|
public func +(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(_bits:
|
|
%if type in floating_types:
|
|
Builtin.fadd_${llvm_vectype}(
|
|
%else:
|
|
Builtin.add_${llvm_vectype}(
|
|
%end
|
|
lhs._vector, rhs._vector))
|
|
}
|
|
|
|
/// Vector difference of `lhs` and `rhs`.
|
|
@inline(__always)
|
|
public func -(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(_bits:
|
|
%if type in floating_types:
|
|
Builtin.fsub_${llvm_vectype}(
|
|
%else:
|
|
Builtin.sub_${llvm_vectype}(
|
|
%end
|
|
lhs._vector, rhs._vector))
|
|
}
|
|
|
|
/// Negation of `rhs`.
|
|
@inline(__always)
|
|
public prefix func -(rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(0) - rhs
|
|
}
|
|
|
|
/// Elementwise product of `lhs` and `rhs`. A.k.a. the Hadamard or Schur
|
|
/// product of the two vectors.
|
|
@inline(__always)
|
|
public func *(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(_bits:
|
|
%if type in floating_types:
|
|
Builtin.fmul_${llvm_vectype}(
|
|
%else:
|
|
Builtin.mul_${llvm_vectype}(
|
|
%end
|
|
lhs._vector, rhs._vector))
|
|
}
|
|
|
|
/// Elementwise quotient of `lhs` and `rhs`. This is the inverse operation
|
|
/// of the elementwise product.
|
|
@inline(__always)
|
|
public func /(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(_bits:
|
|
%if type in floating_types:
|
|
Builtin.fdiv_${llvm_vectype}(
|
|
%else:
|
|
Builtin.sdiv_${llvm_vectype}(
|
|
%end
|
|
lhs._vector, rhs._vector))
|
|
}
|
|
|
|
/// Add `rhs` to `lhs`.
|
|
@inline(__always)
|
|
public func +=(inout lhs: ${vectype}, rhs: ${vectype}) -> Void {
|
|
lhs = lhs + rhs
|
|
}
|
|
|
|
/// Subtract `rhs` from `lhs`.
|
|
@inline(__always)
|
|
public func -=(inout lhs: ${vectype}, rhs: ${vectype}) -> Void {
|
|
lhs = lhs - rhs
|
|
}
|
|
|
|
/// Multiply `lhs` by `rhs` (elementwise).
|
|
@inline(__always)
|
|
public func *=(inout lhs: ${vectype}, rhs: ${vectype}) -> Void {
|
|
lhs = lhs * rhs
|
|
}
|
|
|
|
/// Divide `lhs` by `rhs` (elementwise).
|
|
@inline(__always)
|
|
public func /=(inout lhs: ${vectype}, rhs: ${vectype}) -> Void {
|
|
lhs = lhs / rhs
|
|
}
|
|
|
|
/// Scalar-Vector product.
|
|
@inline(__always)
|
|
public func *(lhs: ${type}, rhs: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(lhs) * rhs
|
|
}
|
|
|
|
/// Scalar-Vector product.
|
|
@inline(__always)
|
|
public func *(lhs: ${vectype}, rhs: ${type}) -> ${vectype} {
|
|
return lhs * ${vectype}(rhs)
|
|
}
|
|
|
|
/// Scales `lhs` by `rhs`.
|
|
@inline(__always)
|
|
public func *=(inout lhs: ${vectype}, rhs: ${type}) -> Void {
|
|
lhs = lhs * rhs
|
|
}
|
|
|
|
/// Elementwise absolute value of a vector. The result is a vector of the same
|
|
/// length with all elements positive.
|
|
@inline(__always)
|
|
public func abs(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'abs(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Elementwise minimum of two vectors. Each component of the result is the
|
|
/// smaller of the corresponding component of the inputs.
|
|
@inline(__always)
|
|
public func min(x: ${vectype}, _ y: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'min(x.' + c + ',y.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Elementwise maximum of two vectors. Each component of the result is the
|
|
/// larger of the corresponding component of the inputs.
|
|
@inline(__always)
|
|
public func max(x: ${vectype}, _ y: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'max(x.' + c + ',y.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Vector-scalar minimum. Each component of the result is the minimum of the
|
|
/// corresponding element of the input vector and the scalar.
|
|
@inline(__always)
|
|
public func min(vector: ${vectype}, _ scalar: ${type}) -> ${vectype} {
|
|
return min(vector, ${vectype}(scalar))
|
|
}
|
|
|
|
/// Vector-scalar maximum. Each component of the result is the maximum of the
|
|
/// corresponding element of the input vector and the scalar.
|
|
@inline(__always)
|
|
public func max(vector: ${vectype}, _ scalar: ${type}) -> ${vectype} {
|
|
return max(vector, ${vectype}(scalar))
|
|
}
|
|
|
|
/// Each component of the result is the corresponding element of `x` clamped to
|
|
/// the range formed by the corresponding elements of `min` and `max`. Any
|
|
/// lanes of `x` that contain NaN will end up with the `min` value.
|
|
@inline(__always)
|
|
public func clamp(x: ${vectype},
|
|
min: ${vectype},
|
|
max: ${vectype})
|
|
-> ${vectype} {
|
|
return simd.min(simd.max(x, min), max)
|
|
}
|
|
|
|
/// Clamp each element of `x` to the range [`min`, max]. If any lane of `x` is
|
|
/// NaN, the corresponding lane of the result is `min`.
|
|
@inline(__always)
|
|
public func clamp(x: ${vectype},
|
|
min: ${type},
|
|
max: ${type})
|
|
-> ${vectype} {
|
|
return simd.min(simd.max(x, min), max)
|
|
}
|
|
|
|
/// Sum of the elements of the vector.
|
|
@inline(__always)
|
|
public func reduce_add(x: ${vectype}) -> ${type} {
|
|
return ${' + '.join(map(lambda x:'x.'+x, component[:size]))}
|
|
}
|
|
|
|
/// Minimum element of the vector.
|
|
@inline(__always)
|
|
public func reduce_min(x: ${vectype}) -> ${type} {
|
|
return min(${', '.join(map(lambda x:'x.'+x, component[:size]))})
|
|
}
|
|
|
|
/// Maximum element of the vector.
|
|
@inline(__always)
|
|
public func reduce_max(x: ${vectype}) -> ${type} {
|
|
return max(${', '.join(map(lambda x:'x.'+x, component[:size]))})
|
|
}
|
|
|
|
% if type in floating_types:
|
|
|
|
/// Sign of a vector. Each lane contains -1 if the corresponding lane of `x`
|
|
/// is less than zero, +1 if the corresponding lane of `x` is greater than
|
|
/// zero, and 0 otherwise.
|
|
@inline(__always)
|
|
public func sign(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'sign(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Linear interpolation between `x` (at `t=0`) and `y` (at `t=1`). May be
|
|
/// used with `t` outside of [0, 1] as well.
|
|
@inline(__always)
|
|
public func mix(x: ${vectype}, _ y: ${vectype}, t: ${vectype}) -> ${vectype} {
|
|
return x + t*(y-x)
|
|
}
|
|
|
|
/// Linear interpolation between `x` (at `t=0`) and `y` (at `t=1`). May be
|
|
/// used with `t` outside of [0, 1] as well.
|
|
@inline(__always)
|
|
public func mix(x: ${vectype}, _ y: ${vectype}, t: ${type}) -> ${vectype} {
|
|
return x + t*(y-x)
|
|
}
|
|
|
|
/// Elementwise reciprocal.
|
|
@inline(__always)
|
|
public func recip(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'recip(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Elementwise reciprocal square root.
|
|
@inline(__always)
|
|
public func rsqrt(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'rsqrt(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Alternate name for minimum of two floating-point vectors.
|
|
@inline(__always)
|
|
public func fmin(x: ${vectype}, _ y: ${vectype}) -> ${vectype} {
|
|
return min(x, y)
|
|
}
|
|
|
|
/// Alternate name for maximum of two floating-point vectors.
|
|
@inline(__always)
|
|
public func fmax(x: ${vectype}, _ y: ${vectype}) -> ${vectype} {
|
|
return max(x, y)
|
|
}
|
|
|
|
/// Each element of the result is the smallest integral value greater than or
|
|
/// equal to the corresponding element of the input.
|
|
@inline(__always)
|
|
public func ceil(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'ceil(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Each element of the result is the largest integral value less than or equal
|
|
/// to the corresponding element of the input.
|
|
@inline(__always)
|
|
public func floor(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'floor(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// Each element of the result is the closest integral value with magnitude
|
|
/// less than or equal to that of the corresponding element of the input.
|
|
@inline(__always)
|
|
public func trunc(x: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'trunc(x.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// `x - floor(x)`, clamped to lie in the range [0,1). Without this clamp step,
|
|
/// the result would be 1.0 when `x` is a very small negative number, which may
|
|
/// result in out-of-bounds table accesses in common usage.
|
|
@inline(__always)
|
|
public func fract(x: ${vectype}) -> ${vectype} {
|
|
return fmin(x - floor(x), ${vectype}(${one_minus_ulp[type]}))
|
|
}
|
|
|
|
/// 0.0 if `x < edge`, and 1.0 otherwise.
|
|
@inline(__always)
|
|
public func step(x: ${vectype}, edge: ${vectype}) -> ${vectype} {
|
|
return ${vectype}(${', '.join(map(lambda c: \
|
|
'step(x.' + c + ', edge: edge.' + c + ')', \
|
|
component[:size]))})
|
|
}
|
|
|
|
/// 0.0 if `x < edge0`, 1.0 if `x > edge1`, and cubic interpolation between
|
|
/// 0 and 1 in the interval [edge0, edge1].
|
|
@inline(__always)
|
|
public func smoothstep(x: ${vectype},
|
|
edge0: ${vectype},
|
|
edge1: ${vectype})
|
|
-> ${vectype} {
|
|
let t = clamp((x-edge0)/(edge1-edge0), min: 0, max: 1)
|
|
return t*t*(${vectype}(3) - 2*t)
|
|
}
|
|
|
|
/// Dot product of `x` and `y`.
|
|
@inline(__always)
|
|
public func dot(x: ${vectype}, _ y: ${vectype}) -> ${type} {
|
|
return reduce_add(x*y)
|
|
}
|
|
|
|
/// Projection of `x` onto `y`.
|
|
@inline(__always)
|
|
public func project(x: ${vectype}, _ y: ${vectype}) -> ${vectype} {
|
|
return dot(x,y)/dot(y,y)*y
|
|
}
|
|
|
|
/// Length of `x`, squared. This is more efficient to compute than the length,
|
|
/// so you should use it if you only need to compare lengths to each other.
|
|
/// I.e. instead of writing:
|
|
///
|
|
/// if (length(x) < length(y)) { ... }
|
|
///
|
|
/// use:
|
|
///
|
|
/// if (length_squared(x) < length_squared(y)) { ... }
|
|
///
|
|
/// Doing it this way avoids one or two square roots, which is a fairly costly
|
|
/// operation.
|
|
@inline(__always)
|
|
public func length_squared(x: ${vectype}) -> ${type} {
|
|
return dot(x,x)
|
|
}
|
|
|
|
/// Length (two-norm or "Euclidean norm") of `x`.
|
|
@inline(__always)
|
|
public func length(x: ${vectype}) -> ${type} {
|
|
return sqrt(length_squared(x))
|
|
}
|
|
|
|
/// The one-norm (or "taxicab norm") of `x`.
|
|
@inline(__always)
|
|
public func norm_one(x: ${vectype}) -> ${type} {
|
|
return reduce_add(abs(x))
|
|
}
|
|
|
|
/// The infinity-norm (or "sup norm") of `x`.
|
|
@inline(__always)
|
|
public func norm_inf(x: ${vectype}) -> ${type} {
|
|
return reduce_max(abs(x))
|
|
}
|
|
|
|
/// Distance between `x` and `y`, squared.
|
|
@inline(__always)
|
|
public func distance_squared(x: ${vectype}, y: ${vectype}) -> ${type} {
|
|
return length_squared(x - y)
|
|
}
|
|
|
|
/// Distance between `x` and `y`.
|
|
@inline(__always)
|
|
public func distance(x: ${vectype}, y: ${vectype}) -> ${type} {
|
|
return length(x - y)
|
|
}
|
|
|
|
/// Unit vector pointing in the same direction as `x`.
|
|
@inline(__always)
|
|
public func normalize(x: ${vectype}) -> ${vectype} {
|
|
return x * rsqrt(length_squared(x))
|
|
}
|
|
|
|
/// `x` reflected through the hyperplane with unit normal vector `n`, passing
|
|
/// through the origin. E.g. if `x` is [1,2,3] and `n` is [0,0,1], the result
|
|
/// is [1,2,-3].
|
|
@inline(__always)
|
|
public func reflect(x: ${vectype}, n: ${vectype}) -> ${vectype} {
|
|
return x - 2*dot(x,n)*n
|
|
}
|
|
|
|
/// The refraction direction given unit incident vector `x`, unit surface
|
|
/// normal `n`, and index of refraction `eta`. If the angle between the
|
|
/// incident vector and the surface is so small that total internal reflection
|
|
/// occurs, zero is returned.
|
|
@inline(__always)
|
|
public func refract(x: ${vectype},
|
|
n: ${vectype},
|
|
eta: ${type})
|
|
-> ${vectype} {
|
|
let k = 1 - eta*eta*(1 - dot(x,n)*dot(x,n))
|
|
if k >= 0 { return eta*x - (eta*dot(x,n) + sqrt(k))*n }
|
|
return ${vectype}(0)
|
|
}
|
|
|
|
% end # if type in floating_types
|
|
% end # for size in [2, 3, 4]
|
|
% if type in floating_types:
|
|
// Scalar versions of common operations:
|
|
|
|
/// Returns -1 if `x < 0`, +1 if `x > 0`, and 0 otherwise (`sign(NaN)` is 0).
|
|
@inline(__always)
|
|
public func sign(x: ${type}) -> ${type} {
|
|
return x < 0 ? -1 : (x > 0 ? 1 : 0)
|
|
}
|
|
|
|
/// Reciprocal.
|
|
@inline(__always)
|
|
public func recip(x: ${type}) -> ${type} { return 1/x }
|
|
|
|
/// Reciprocal square root.
|
|
@inline(__always)
|
|
public func rsqrt(x: ${type}) -> ${type} { return 1/sqrt(x) }
|
|
|
|
/// Returns 0.0 if `x < edge`, and 1.0 otherwise.
|
|
@inline(__always)
|
|
public func step(x: ${type}, edge: ${type}) -> ${type} {
|
|
return x < edge ? 0.0 : 1.0
|
|
}
|
|
|
|
/// Interprets two two-dimensional vectors as three-dimensional vectors in the
|
|
/// xy-plane and computes their cross product, which lies along the z-axis.
|
|
@inline(__always)
|
|
public func cross(x: ${ctype[type]}2,
|
|
_ y: ${ctype[type]}2)
|
|
-> ${ctype[type]}3 {
|
|
return ${ctype[type]}3(0, 0, x.x*y.y - x.y*y.x)
|
|
}
|
|
|
|
/// Cross-product of two three-dimensional vectors. The resulting vector is
|
|
/// perpendicular to the plane determined by `x` and `y`, with length equal to
|
|
/// the oriented area of the parallelogram they determine.
|
|
@inline(__always)
|
|
public func cross(x: ${ctype[type]}3,
|
|
_ y: ${ctype[type]}3)
|
|
-> ${ctype[type]}3 {
|
|
return ${ctype[type]}3(x.y*y.z - x.z*y.y, x.z*y.x - x.x*y.z, x.x*y.y - x.y*y.x)
|
|
}
|
|
% end # type in floating_types
|
|
% end # for type in scalar_types
|
|
|
|
% for type in floating_types:
|
|
% for rows in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% for cols in [2,3,4]:
|
|
// Workaround <rdar://problem/18900352>
|
|
% mattype = ctype[type] + str(cols) + 'x' + str(rows)
|
|
% diagsize = rows if rows < cols else cols
|
|
% coltype = ctype[type] + str(rows)
|
|
% rowtype = ctype[type] + str(cols)
|
|
% diagtype = ctype[type] + str(diagsize)
|
|
% transtype = ctype[type] + str(rows) + 'x' + str(cols)
|
|
% cmatrix = 'matrix_' + mattype
|
|
|
|
public struct ${mattype} : CustomDebugStringConvertible {
|
|
|
|
internal var _columns: (${', '.join([coltype]*cols)})
|
|
|
|
/// Initialize matrix to zero.
|
|
public init() {
|
|
% for i in range(cols):
|
|
_columns.${i} = ${coltype}()
|
|
% end
|
|
}
|
|
|
|
/// Initialize matrix to have `scalar` on main diagonal, zeros elsewhere.
|
|
public init(_ scalar: ${type}) {
|
|
self.init(diagonal: ${diagtype}(scalar))
|
|
}
|
|
|
|
/// Initialize matrix to have specified `diagonal`, and zeros elsewhere.
|
|
public init(diagonal: ${diagtype}) {
|
|
% for i in range(cols):
|
|
self._columns.${i} = ${coltype}()
|
|
% end
|
|
% for i in range(diagsize):
|
|
self._columns.${i}.${component[i]} = diagonal.${component[i]}
|
|
% end
|
|
}
|
|
|
|
/// Initialize matrix to have specified `columns`.
|
|
public init(_ columns: [${coltype}]) {
|
|
_precondition(columns.count == ${cols}, "Requires array of ${cols} vectors")
|
|
% for i in range(cols):
|
|
self._columns.${i} = columns[${i}]
|
|
% end
|
|
}
|
|
|
|
/// Initialize matrix to have specified `rows`.
|
|
public init(rows: [${rowtype}]) {
|
|
_precondition(rows.count == ${rows}, "Requires array of ${rows} vectors")
|
|
% for i in range(cols):
|
|
self._columns.${i} = [${', '.join(map(lambda j:
|
|
'rows[' + str(j) + '].' + component[i],
|
|
range(rows)))}]
|
|
% end
|
|
}
|
|
|
|
/// Initialize matrix to have specified `columns`.
|
|
internal init(${', '.join(map(lambda i:
|
|
'_ col' + str(i) + ': ' + coltype,
|
|
range(cols)))}) {
|
|
% for i in range(cols):
|
|
self._columns.${i} = col${i}
|
|
% end
|
|
}
|
|
|
|
/// Initialize matrix from corresponding C matrix type.
|
|
public init(_ cmatrix: ${cmatrix}) {
|
|
self = unsafeBitCast(cmatrix, ${mattype}.self)
|
|
}
|
|
|
|
/// Get the matrix as the corresponding C matrix type.
|
|
public var cmatrix: ${cmatrix} {
|
|
get { return unsafeBitCast(self, ${cmatrix}.self) }
|
|
}
|
|
|
|
/// Access to individual columns.
|
|
public subscript(column: Int) -> ${coltype} {
|
|
get {
|
|
switch(column) {
|
|
% for i in range(cols):
|
|
case ${i}: return _columns.${i}
|
|
% end
|
|
default: _preconditionFailure("Column index out of range")
|
|
}
|
|
}
|
|
set (value) {
|
|
switch(column) {
|
|
% for i in range(cols):
|
|
case ${i}: _columns.${i} = value
|
|
% end
|
|
default: _preconditionFailure("Column index out of range")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Access to individual elements.
|
|
public subscript(column: Int, row: Int) -> ${type} {
|
|
get { return self[column][row] }
|
|
set (value) { self[column][row] = value }
|
|
}
|
|
|
|
public var debugDescription: String {
|
|
return "${mattype}([${', '.join(map(lambda i: \
|
|
'\(_columns.' + str(i) + '._descriptionAsArray)',
|
|
range(cols)))}])"
|
|
}
|
|
|
|
/// Transpose of the matrix.
|
|
public var transpose: ${transtype} {
|
|
get {
|
|
return ${transtype}([
|
|
% for i in range(rows):
|
|
[${', '.join(map(lambda j: \
|
|
'self[' + str(j) + ',' + str(i) + ']', \
|
|
range(cols)))}],
|
|
% end # for i in range(rows)
|
|
])
|
|
}
|
|
}
|
|
|
|
% if rows == cols:
|
|
/// Inverse of the matrix if it exists, otherwise the contents of the
|
|
/// resulting matrix are undefined.
|
|
public var inverse: ${mattype} {
|
|
get {
|
|
% inverse_func = '__invert_' + ('f' if type == 'Float' else 'd') + str(cols)
|
|
return ${mattype}(${inverse_func}(self.cmatrix))
|
|
}
|
|
}
|
|
% end
|
|
}
|
|
|
|
/// Sum of two matrices.
|
|
public func +(lhs: ${mattype}, rhs: ${mattype}) -> ${mattype} {
|
|
return ${mattype}(${', '.join(map(lambda i: \
|
|
'lhs._columns.'+str(i)+' + rhs._columns.'+str(i), \
|
|
range(cols)))})
|
|
}
|
|
|
|
/// Negation of a matrix.
|
|
public prefix func -(rhs: ${mattype}) -> ${mattype} {
|
|
return ${mattype}(${', '.join(map(lambda i: \
|
|
'-rhs._columns.'+str(i), \
|
|
range(cols)))})
|
|
}
|
|
|
|
/// Difference of two matrices.
|
|
public func -(lhs: ${mattype}, rhs: ${mattype}) -> ${mattype} {
|
|
return ${mattype}(${', '.join(map(lambda i: \
|
|
'lhs._columns.'+str(i)+' - rhs._columns.'+str(i), \
|
|
range(cols)))})
|
|
}
|
|
|
|
public func +=(inout lhs: ${mattype}, rhs: ${mattype}) -> Void {
|
|
lhs = lhs + rhs
|
|
}
|
|
|
|
public func -=(inout lhs: ${mattype}, rhs: ${mattype}) -> Void {
|
|
lhs = lhs - rhs;
|
|
}
|
|
|
|
/// Scalar-Matrix multiplication.
|
|
public func *(lhs: ${type}, rhs: ${mattype}) -> ${mattype} {
|
|
return ${mattype}(${', '.join(map(lambda i: \
|
|
'lhs*rhs._columns.'+str(i), \
|
|
range(cols)))})
|
|
}
|
|
|
|
/// Matrix-Scalar multiplication.
|
|
public func *(lhs: ${mattype}, rhs: ${type}) -> ${mattype} {
|
|
return rhs*lhs
|
|
}
|
|
|
|
public func *=(inout lhs: ${mattype}, rhs: ${type}) -> Void {
|
|
lhs = lhs*rhs
|
|
}
|
|
|
|
/// Matrix-Vector multiplication. Keep in mind that matrix types are named
|
|
/// `${type}NxM` where `N` is the number of *columns* and `M` is the number of
|
|
/// *rows*, so we multiply a `${type}3x2 * ${type}3` to get a `${type}2`, for
|
|
/// example.
|
|
public func *(lhs: ${mattype}, rhs: ${rowtype}) -> ${coltype} {
|
|
return ${' + '.join(map(lambda i: \
|
|
'lhs._columns.'+str(i)+'*rhs.'+component[i], \
|
|
range(cols)))}
|
|
}
|
|
|
|
/// Vector-Matrix multiplication.
|
|
public func *(lhs: ${coltype}, rhs: ${mattype}) -> ${rowtype} {
|
|
return ${rowtype}(${', '.join(map(lambda i: \
|
|
'dot(lhs, rhs._columns.'+str(i)+')', \
|
|
range(cols)))})
|
|
}
|
|
|
|
% for k in [2,3,4]:
|
|
/// Matrix multiplication (the "usual" matrix product, not the elementwise
|
|
/// product).
|
|
% lhstype = ctype[type] + str(k) + 'x' + str(rows)
|
|
% rhstype = ctype[type] + str(cols) + 'x' + str(k)
|
|
public func *(lhs: ${lhstype}, rhs: ${rhstype}) -> ${mattype} {
|
|
return ${mattype}(${', '.join(map(lambda i: \
|
|
'lhs*rhs._columns.'+str(i), \
|
|
range(cols)))})
|
|
}
|
|
|
|
% end # for k in [2,3,4]
|
|
|
|
% rhstype = ctype[type] + str(cols) + 'x' + str(cols)
|
|
/// Matrix multiplication (the "usual" matrix product, not the elementwise
|
|
/// product).
|
|
public func *=(inout lhs: ${mattype}, rhs: ${rhstype}) -> Void {
|
|
lhs = lhs*rhs
|
|
}
|
|
|
|
% end # for cols in [2,3,4]
|
|
% end # for rows in [2,3,4]
|
|
% end # for type in floating_types
|