| //===----------------------------------------------------------*- swift -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://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','UInt32'] |
| ctype = { 'Float':'float', 'Double':'double', 'Int32':'int', 'UInt32':'uint'} |
| llvm_type = { 'Float':'FPIEEE32', 'Double':'FPIEEE64', 'Int32':'Int32', 'UInt32':'Int32' } |
| floating_types = ['Float','Double'] |
| cardinal = { 2:'two', 3:'three', 4:'four'} |
| }% |
| |
| %for scalar in scalar_types: |
| % for count in [2, 3, 4]: |
| % vectype = ctype[scalar] + str(count) |
| % llvm_vectype = "Vec" + str(count) + "x" + llvm_type[scalar] |
| % vecsize = (8 if scalar == 'Double' else 4) * (4 if count == 3 else count) |
| % extractelement = "extractelement_" + llvm_vectype + "_Int32" |
| % insertelement = "insertelement_" + llvm_vectype + "_" + llvm_type[scalar] + "_Int32" |
| % is_floating = scalar in floating_types |
| % is_signed = scalar[0] != 'U' |
| % wrap = "" if is_floating else "&" |
| |
| |
| /// A vector of ${cardinal[count]} `${scalar}`. This corresponds to the C and |
| /// Obj-C type `vector_${vectype}` and the C++ type `simd::${vectype}`. |
| @_fixed_layout |
| @_alignment(${vecsize}) |
| public struct ${vectype} { |
| |
| public var _vector: Builtin.${llvm_vectype} |
| |
| % for i in xrange(count): |
| public var ${component[i]} : ${scalar} { |
| @_transparent |
| get { |
| let elt = Builtin.${extractelement}(_vector, |
| (${i} as Int32)._value) |
| |
| return ${scalar}(_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(['_ ' + c + ': ' + scalar for c in component[:count]])}) { |
| var v: Builtin.${llvm_vectype} = Builtin.zeroInitializer() |
| % for i in xrange(count): |
| 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([c + ': ' + scalar for c in component[:count]])}) { |
| self.init(${', '.join(component[:count])}) |
| } |
| |
| /// Initialize to a vector with all elements equal to `scalar`. |
| @_transparent |
| public init(_ scalar: ${scalar}) { |
| self.init(${', '.join(['scalar']*count)}) |
| } |
| |
| /// Initialize to a vector with elements taken from `array`. |
| /// |
| /// - Precondition: `array` must have exactly ${cardinal[count]} elements. |
| public init(_ array: [${scalar}]) { |
| _precondition(array.count == ${count}, |
| "${vectype} requires a ${cardinal[count]}-element array") |
| self.init(${', '.join(map(lambda i: |
| 'array[' + str(i) + ']', |
| range(count)))}) |
| } |
| |
| /// Access individual elements of the vector via subscript. |
| public subscript(index: Int) -> ${scalar} { |
| @_transparent |
| get { |
| _precondition(index >= 0, "Vector index out of range") |
| _precondition(index < ${count}, "Vector index out of range") |
| let elt = Builtin.${extractelement}(_vector, |
| Int32(index)._value) |
| return ${scalar}(_bits: elt) |
| } |
| @_transparent |
| set(value) { |
| _precondition(index >= 0, "Vector index out of range") |
| _precondition(index < ${count}, "Vector index out of range") |
| _vector = Builtin.${insertelement}(_vector, |
| value._value, |
| Int32(index)._value) |
| } |
| } |
| } |
| |
| extension ${vectype} : Equatable { |
| /// True iff every element of lhs is equal to the corresponding element of |
| /// rhs. |
| @_transparent |
| public static func ==(_ lhs: ${vectype}, _ rhs: ${vectype}) -> Bool { |
| return simd_equal(lhs, rhs) |
| } |
| } |
| |
| extension ${vectype} : CustomDebugStringConvertible { |
| /// Debug string representation |
| public var debugDescription: String { |
| return "${vectype}(${', '.join(map(lambda c: |
| '\\(self['+ str(c) + '])', |
| xrange(count)))})" |
| } |
| |
| % if count <= 4: |
| /// Helper for matrix debug representations |
| internal var _descriptionAsArray: String { |
| get { |
| return "[${', '.join(map(lambda c: |
| '\\(self['+ str(c) + '])', |
| xrange(count)))})]" |
| } |
| } |
| % end |
| } |
| |
| extension ${vectype} : ExpressibleByArrayLiteral { |
| /// Initialize using `arrayLiteral`. |
| /// |
| /// - Precondition: the array literal must exactly ${cardinal[count]} |
| /// elements. |
| public init(arrayLiteral elements: ${scalar}...) { self.init(elements) } |
| } |
| |
| extension ${vectype} : Collection { |
| @_transparent |
| public var startIndex: Int { return 0 } |
| |
| @_transparent |
| public var endIndex: Int { return ${count} } |
| |
| @_transparent |
| public func index(after i: Int) -> Int { return i + 1 } |
| } |
| |
| extension ${vectype} { |
| % wrap = "" if is_floating else "&" |
| % prefix = "f" if is_floating else "" |
| % divide = ("f" if is_floating else ("s" if is_signed else "u")) + "div" |
| /// Vector (elementwise) sum of `lhs` and `rhs`. |
| @_transparent |
| public static func ${wrap}+(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}(_bits: |
| Builtin.${prefix}add_${llvm_vectype}(lhs._vector, rhs._vector)) |
| } |
| |
| /// Vector (elementwise) difference of `lhs` and `rhs`. |
| @_transparent |
| public static func ${wrap}-(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}(_bits: |
| Builtin.${prefix}sub_${llvm_vectype}(lhs._vector, rhs._vector)) |
| } |
| |
| /// Negation of `rhs`. |
| @_transparent |
| public static prefix func -(rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}() ${wrap}- rhs |
| } |
| |
| /// Elementwise product of `lhs` and `rhs` (A.k.a. the Hadamard or Schur |
| /// vector product). |
| @_transparent |
| public static func ${wrap}*(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}(_bits: |
| Builtin.${prefix}mul_${llvm_vectype}(lhs._vector, rhs._vector)) |
| } |
| |
| /// Scalar-Vector product. |
| @_transparent |
| public static func ${wrap}*(lhs: ${scalar}, rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}(lhs) ${wrap}* rhs |
| } |
| |
| /// Scalar-Vector product. |
| @_transparent |
| public static func ${wrap}*(lhs: ${vectype}, rhs: ${scalar}) -> ${vectype} { |
| return lhs ${wrap}* ${vectype}(rhs) |
| } |
| |
| /// Elementwise quotient of `lhs` and `rhs`. |
| @_transparent |
| public static func /(lhs: ${vectype}, rhs: ${vectype}) -> ${vectype} { |
| return ${vectype}(_bits: |
| Builtin.${divide}_${llvm_vectype}(lhs._vector, rhs._vector)) |
| } |
| |
| /// Divide vector by scalar. |
| @_transparent |
| public static func /(lhs: ${vectype}, rhs: ${scalar}) -> ${vectype} { |
| return lhs / ${vectype}(rhs) |
| } |
| |
| /// Add `rhs` to `lhs`. |
| % if is_floating: |
| @_transparent |
| public static func +=(lhs: inout ${vectype}, rhs: ${vectype}) -> Void { |
| lhs = lhs + rhs |
| } |
| |
| /// Subtract `rhs` from `lhs`. |
| @_transparent |
| public static func -=(lhs: inout ${vectype}, rhs: ${vectype}) -> Void { |
| lhs = lhs - rhs |
| } |
| |
| /// Multiply `lhs` by `rhs` (elementwise). |
| @_transparent |
| public static func *=(lhs: inout ${vectype}, rhs: ${vectype}) -> Void { |
| lhs = lhs * rhs |
| } |
| % end |
| |
| /// Divide `lhs` by `rhs` (elementwise). |
| @_transparent |
| public static func /=(lhs: inout ${vectype}, rhs: ${vectype}) -> Void { |
| lhs = lhs / rhs |
| } |
| |
| % if is_floating: |
| /// Scales `lhs` by `rhs`. |
| @_transparent |
| public static func *=(lhs: inout ${vectype}, rhs: ${scalar}) -> Void { |
| lhs = lhs * rhs |
| } |
| |
| /// Scales `lhs` by `1/rhs`. |
| @_transparent |
| public static func /=(lhs: inout ${vectype}, rhs: ${scalar}) -> Void { |
| lhs = lhs / rhs |
| } |
| % else: |
| // Integer vector types only support wrapping arithmetic. Make the non- |
| // wrapping operators unavailable so that fixits guide users to the |
| // unchecked operations. |
| |
| @available(*, unavailable, renamed: "&+", |
| message: "integer vector types do not support checked arithmetic; use the wrapping operations instead") |
| public static func +(x: ${vectype}, y: ${vectype}) -> ${vectype} { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, renamed: "&-", |
| message: "integer vector types do not support checked arithmetic; use the wrapping operations instead") |
| public static func -(x: ${vectype}, y: ${vectype}) -> ${vectype} { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, renamed: "&*", |
| message: "integer vector types do not support checked arithmetic; use the wrapping operations instead") |
| public static func *(x: ${vectype}, y: ${vectype}) -> ${vectype} { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, renamed: "&*", |
| message: "integer vector types do not support checked arithmetic; use the wrapping operations instead") |
| public static func *(x: ${vectype}, y: ${scalar}) -> ${vectype} { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, renamed: "&*", |
| message: "integer vector types do not support checked arithmetic; use the wrapping operations instead") |
| public static func *(x: ${scalar}, y: ${vectype}) -> ${vectype} { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, |
| message: "integer vector types do not support checked arithmetic; use the wrapping operation 'x = x &+ y' instead") |
| public static func +=(x: inout ${vectype}, y: ${vectype}) { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, |
| message: "integer vector types do not support checked arithmetic; use the wrapping operation 'x = x &- y' instead") |
| public static func -=(x: inout ${vectype}, y: ${vectype}) { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, |
| message: "integer vector types do not support checked arithmetic; use the wrapping operation 'x = x &* y' instead") |
| public static func *=(x: inout ${vectype}, y: ${vectype}) { |
| fatalError("Unavailable function cannot be called") |
| } |
| |
| @available(*, unavailable, |
| message: "integer vector types do not support checked arithmetic; use the wrapping operation 'x = x &* y' instead") |
| public static func *=(x: inout ${vectype}, y: ${scalar}) { |
| fatalError("Unavailable function cannot be called") |
| } |
| % end |
| } |
| |
| % if is_signed: |
| /// Elementwise absolute value of a vector. The result is a vector of the same |
| /// length with all elements positive. |
| @_transparent |
| public func abs(_ x: ${vectype}) -> ${vectype} { |
| return simd_abs(x) |
| } |
| % end |
| |
| /// Elementwise minimum of two vectors. Each component of the result is the |
| /// smaller of the corresponding component of the inputs. |
| @_transparent |
| public func min(_ x: ${vectype}, _ y: ${vectype}) -> ${vectype} { |
| return simd_min(x, y) |
| } |
| |
| /// Elementwise maximum of two vectors. Each component of the result is the |
| /// larger of the corresponding component of the inputs. |
| @_transparent |
| public func max(_ x: ${vectype}, _ y: ${vectype}) -> ${vectype} { |
| return simd_max(x, y) |
| } |
| |
| /// Vector-scalar minimum. Each component of the result is the minimum of the |
| /// corresponding element of the input vector and the scalar. |
| @_transparent |
| public func min(_ vector: ${vectype}, _ scalar: ${scalar}) -> ${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. |
| @_transparent |
| public func max(_ vector: ${vectype}, _ scalar: ${scalar}) -> ${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. |
| @_transparent |
| 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`. |
| @_transparent |
| public func clamp(_ x: ${vectype}, min: ${scalar}, max: ${scalar}) |
| -> ${vectype} { |
| return simd.min(simd.max(x, min), max) |
| } |
| |
| /// Sum of the elements of the vector. |
| @_transparent |
| public func reduce_add(_ x: ${vectype}) -> ${scalar} { |
| return simd_reduce_add(x) |
| } |
| |
| /// Minimum element of the vector. |
| @_transparent |
| public func reduce_min(_ x: ${vectype}) -> ${scalar} { |
| return simd_reduce_min(x) |
| } |
| |
| /// Maximum element of the vector. |
| @_transparent |
| public func reduce_max(_ x: ${vectype}) -> ${scalar} { |
| return simd_reduce_max(x) |
| } |
| |
| % if is_floating: |
| |
| /// 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. |
| @_transparent |
| public func sign(_ x: ${vectype}) -> ${vectype} { |
| return simd_sign(x) |
| } |
| |
| /// Linear interpolation between `x` (at `t=0`) and `y` (at `t=1`). May be |
| /// used with `t` outside of [0, 1] as well. |
| @_transparent |
| 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. |
| @_transparent |
| public func mix(_ x: ${vectype}, _ y: ${vectype}, t: ${scalar}) -> ${vectype} { |
| return x + t*(y-x) |
| } |
| |
| /// Elementwise reciprocal. |
| @_transparent |
| public func recip(_ x: ${vectype}) -> ${vectype} { |
| return simd_recip(x) |
| } |
| |
| /// Elementwise reciprocal square root. |
| @_transparent |
| public func rsqrt(_ x: ${vectype}) -> ${vectype} { |
| return simd_rsqrt(x) |
| } |
| |
| /// Alternate name for minimum of two floating-point vectors. |
| @_transparent |
| public func fmin(_ x: ${vectype}, _ y: ${vectype}) -> ${vectype} { |
| return min(x, y) |
| } |
| |
| /// Alternate name for maximum of two floating-point vectors. |
| @_transparent |
| 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. |
| @_transparent |
| public func ceil(_ x: ${vectype}) -> ${vectype} { |
| return __tg_ceil(x) |
| } |
| |
| /// Each element of the result is the largest integral value less than or equal |
| /// to the corresponding element of the input. |
| @_transparent |
| public func floor(_ x: ${vectype}) -> ${vectype} { |
| return __tg_floor(x) |
| } |
| |
| /// 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. |
| @_transparent |
| public func trunc(_ x: ${vectype}) -> ${vectype} { |
| return __tg_trunc(x) |
| } |
| |
| /// `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. |
| @_transparent |
| public func fract(_ x: ${vectype}) -> ${vectype} { |
| return simd_fract(x) |
| } |
| |
| /// 0.0 if `x < edge`, and 1.0 otherwise. |
| @_transparent |
| public func step(_ x: ${vectype}, edge: ${vectype}) -> ${vectype} { |
| return simd_step(edge, x) |
| } |
| |
| /// 0.0 if `x < edge0`, 1.0 if `x > edge1`, and cubic interpolation between |
| /// 0 and 1 in the interval [edge0, edge1]. |
| @_transparent |
| public func smoothstep(_ x: ${vectype}, edge0: ${vectype}, edge1: ${vectype}) |
| -> ${vectype} { |
| return simd_smoothstep(edge0, edge1, x) |
| } |
| |
| /// Dot product of `x` and `y`. |
| @_transparent |
| public func dot(_ x: ${vectype}, _ y: ${vectype}) -> ${scalar} { |
| return reduce_add(x * y) |
| } |
| |
| /// Projection of `x` onto `y`. |
| @_transparent |
| public func project(_ x: ${vectype}, _ y: ${vectype}) -> ${vectype} { |
| return simd_project(x, 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. |
| @_transparent |
| public func length_squared(_ x: ${vectype}) -> ${scalar} { |
| return dot(x, x) |
| } |
| |
| /// Length (two-norm or "Euclidean norm") of `x`. |
| @_transparent |
| public func length(_ x: ${vectype}) -> ${scalar} { |
| return sqrt(length_squared(x)) |
| } |
| |
| /// The one-norm (or "taxicab norm") of `x`. |
| @_transparent |
| public func norm_one(_ x: ${vectype}) -> ${scalar} { |
| return reduce_add(abs(x)) |
| } |
| |
| /// The infinity-norm (or "sup norm") of `x`. |
| @_transparent |
| public func norm_inf(_ x: ${vectype}) -> ${scalar} { |
| return reduce_max(abs(x)) |
| } |
| |
| /// Distance between `x` and `y`, squared. |
| @_transparent |
| public func distance_squared(_ x: ${vectype}, _ y: ${vectype}) -> ${scalar} { |
| return length_squared(x - y) |
| } |
| |
| /// Distance between `x` and `y`. |
| @_transparent |
| public func distance(_ x: ${vectype}, _ y: ${vectype}) -> ${scalar} { |
| return length(x - y) |
| } |
| |
| /// Unit vector pointing in the same direction as `x`. |
| @_transparent |
| public func normalize(_ x: ${vectype}) -> ${vectype} { |
| return simd_normalize(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]. |
| @_transparent |
| public func reflect(_ x: ${vectype}, n: ${vectype}) -> ${vectype} { |
| return simd_reflect(x, 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. |
| @_transparent |
| public func refract(_ x: ${vectype}, n: ${vectype}, eta: ${scalar}) |
| -> ${vectype} { |
| return simd_refract(x, n, eta) |
| } |
| |
| % end # if is_floating |
| % end # for count in [2, 3, 4] |
| % if is_floating: |
| // Scalar versions of common operations: |
| |
| /// Returns -1 if `x < 0`, +1 if `x > 0`, and 0 otherwise (`sign(NaN)` is 0). |
| @_transparent |
| public func sign(_ x: ${scalar}) -> ${scalar} { |
| return simd_sign(x) |
| } |
| |
| /// Reciprocal. |
| @_transparent |
| public func recip(_ x: ${scalar}) -> ${scalar} { |
| return simd_recip(x) |
| } |
| |
| /// Reciprocal square root. |
| @_transparent |
| public func rsqrt(_ x: ${scalar}) -> ${scalar} { |
| return simd_rsqrt(x) |
| } |
| |
| /// Returns 0.0 if `x < edge`, and 1.0 otherwise. |
| @_transparent |
| public func step(_ x: ${scalar}, edge: ${scalar}) -> ${scalar} { |
| return simd_step(edge, x) |
| } |
| |
| /// Interprets two two-dimensional vectors as three-dimensional vectors in the |
| /// xy-plane and computes their cross product, which lies along the z-axis. |
| @_transparent |
| public func cross(_ x: ${ctype[scalar]}2, _ y: ${ctype[scalar]}2) |
| -> ${ctype[scalar]}3 { |
| return simd_cross(x,y) |
| } |
| |
| /// 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. |
| @_transparent |
| public func cross(_ x: ${ctype[scalar]}3, _ y: ${ctype[scalar]}3) |
| -> ${ctype[scalar]}3 { |
| return simd_cross(x,y) |
| } |
| |
| % end # is_floating |
| %end # for scalar in scalar_types |
| |
| %for type in floating_types: |
| % for rows in [2,3,4]: |
| % for cols in [2,3,4]: |
| % mattype = 'simd_' + 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) |
| |
| public typealias ${ctype[type]}${cols}x${rows} = ${mattype} |
| |
| extension ${mattype} { |
| |
| /// 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}) { |
| self.init() |
| % 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") |
| self.init() |
| % 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") |
| self = ${transtype}(rows).transpose |
| } |
| |
| /// Initialize matrix to have specified `columns`. |
| public init(${', '.join(['_ col' + str(i) + ': ' + coltype |
| for i in range(cols)])}) { |
| self.init() |
| % for i in range(cols): |
| self.columns.${i} = col${i} |
| % end |
| } |
| |
| /// Initialize matrix from corresponding C matrix type. |
| @available(swift, deprecated: 4, message: "This conversion is no longer necessary; use `cmatrix` directly.") |
| @_transparent |
| public init(_ cmatrix: ${mattype}) { |
| self = cmatrix |
| } |
| |
| /// Get the matrix as the corresponding C matrix type. |
| @available(swift, deprecated: 4, message: "This property is no longer needed; use the matrix itself.") |
| @_transparent |
| public var cmatrix: ${mattype} { |
| return 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 } |
| } |
| } |
| |
| extension ${mattype} : CustomDebugStringConvertible { |
| public var debugDescription: String { |
| return "${mattype}([${', '.join(map(lambda i: \ |
| '\(columns.' + str(i) + '._descriptionAsArray)', |
| range(cols)))}])" |
| } |
| } |
| |
| extension ${mattype} : Equatable { |
| @_transparent |
| public static func ==(lhs: ${mattype}, rhs: ${mattype}) -> Bool { |
| return simd_equal(lhs, rhs) |
| } |
| } |
| |
| extension ${mattype} { |
| |
| /// Transpose of the matrix. |
| @_transparent |
| public var transpose: ${transtype} { |
| return simd_transpose(self) |
| } |
| |
| % if rows == cols: |
| /// Inverse of the matrix if it exists, otherwise the contents of the |
| /// resulting matrix are undefined. |
| @available(OSX 10.10, iOS 8.0, tvOS 10.0, watchOS 3.0, *) |
| @_transparent |
| public var inverse: ${mattype} { |
| return simd_inverse(self) |
| } |
| |
| /// Determinant of the matrix. |
| @_transparent |
| public var determinant: ${type} { |
| return simd_determinant(self) |
| } |
| % end |
| |
| /// Sum of two matrices. |
| @_transparent |
| public static func +(lhs: ${mattype}, rhs: ${mattype}) -> ${mattype} { |
| return simd_add(lhs, rhs) |
| } |
| |
| /// Negation of a matrix. |
| @_transparent |
| public static prefix func -(rhs: ${mattype}) -> ${mattype} { |
| return ${mattype}() - rhs |
| } |
| |
| /// Difference of two matrices. |
| @_transparent |
| public static func -(lhs: ${mattype}, rhs: ${mattype}) -> ${mattype} { |
| return simd_sub(lhs, rhs) |
| } |
| |
| @_transparent |
| public static func +=(lhs: inout ${mattype}, rhs: ${mattype}) -> Void { |
| lhs = lhs + rhs |
| } |
| |
| @_transparent |
| public static func -=(lhs: inout ${mattype}, rhs: ${mattype}) -> Void { |
| lhs = lhs - rhs |
| } |
| |
| /// Scalar-Matrix multiplication. |
| @_transparent |
| public static func *(lhs: ${type}, rhs: ${mattype}) -> ${mattype} { |
| return simd_mul(lhs, rhs) |
| } |
| |
| /// Matrix-Scalar multiplication. |
| @_transparent |
| public static func *(lhs: ${mattype}, rhs: ${type}) -> ${mattype} { |
| return rhs*lhs |
| } |
| |
| @_transparent |
| public static func *=(lhs: inout ${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. |
| @_transparent |
| public static func *(lhs: ${mattype}, rhs: ${rowtype}) -> ${coltype} { |
| return simd_mul(lhs, rhs) |
| } |
| |
| /// Vector-Matrix multiplication. |
| @_transparent |
| public static func *(lhs: ${coltype}, rhs: ${mattype}) -> ${rowtype} { |
| return simd_mul(lhs, rhs) |
| } |
| |
| % for k in [2,3,4]: |
| /// Matrix multiplication (the "usual" matrix product, not the elementwise |
| /// product). |
| % restype = ctype[type] + str(k) + 'x' + str(rows) |
| % rhstype = ctype[type] + str(k) + 'x' + str(cols) |
| @_transparent |
| public static func *(lhs: ${mattype}, rhs: ${rhstype}) -> ${restype} { |
| return simd_mul(lhs, rhs) |
| } |
| |
| % 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). |
| @_transparent |
| public static func *=(lhs: inout ${mattype}, rhs: ${rhstype}) -> Void { |
| lhs = lhs*rhs |
| } |
| } |
| |
| // Make old-style C free functions with the `matrix_` prefix available but |
| // deprecated in Swift 4. |
| |
| % if rows == cols: |
| @available(swift, deprecated: 4, renamed: "${mattype}(diagonal:)") |
| public func matrix_from_diagonal(_ d: ${diagtype}) -> ${mattype} { |
| return ${mattype}(diagonal: d) |
| } |
| |
| @available(swift, deprecated: 4, message: "Use the .inverse property instead.") |
| @available(OSX 10.10, iOS 8.0, tvOS 10.0, watchOS 3.0, *) |
| public func matrix_invert(_ x: ${mattype}) -> ${mattype} { |
| return x.inverse |
| } |
| |
| @available(swift, deprecated: 4, message: "Use the .determinant property instead.") |
| public func matrix_determinant(_ x: ${mattype}) -> ${type} { |
| return x.determinant |
| } |
| |
| % end # rows == cols |
| @available(swift, deprecated: 4, renamed: "${mattype}") |
| public func matrix_from_columns(${', '.join(['_ col' + str(i) + ': ' + coltype |
| for i in range(cols)])}) -> ${mattype} { |
| return ${mattype}(${', '.join(['col' + str(i) for i in range(cols)])}) |
| } |
| |
| public func matrix_from_rows(${', '.join(['_ row' + str(i) + ': ' + rowtype |
| for i in range(rows)])}) -> ${mattype} { |
| return ${transtype}(${', '.join(['row' + str(i) for i in range(rows)])}).transpose |
| } |
| |
| @available(swift, deprecated: 4, message: "Use the .transpose property instead.") |
| public func matrix_transpose(_ x: ${mattype}) -> ${transtype} { |
| return x.transpose |
| } |
| |
| @available(swift, deprecated: 4, renamed: "==") |
| public func matrix_equal(_ lhs: ${mattype}, _ rhs: ${mattype}) -> Bool { |
| return lhs == rhs |
| } |
| |
| % end # for cols in [2,3,4] |
| % end # for rows in [2,3,4] |
| %end # for type in floating_types |