SE-0229 — SIMD Vectors

CGFloat can already participate by conforming to SIMDVectorizable. I'm not sure what this additional protocol would add.

Might it be a good idea to consider allowing the user to specify the convenience labels appropriate to their domain? The elements could alway be accessed by index as usual.

let v1= Vector3<Double, "xyz"> //3d cartesian
//v1.x, v1.y, v1.z are valid accessors

let v2 = Vector3<Double, "rθϕ">; //spherical
//v2.r, v2.θ, v1.ϕ are valid accessors

let v3 = Vector3<Double, "xyw"> //3d homogenous representation of 2d object

let v4 = Vector4<Double, "xyzt"> //cartesian plus time

let v5 = Vector4<Double, "rgba"> //color

I'm not sure if I think this is a good idea or not, but it's not something we'd be able to implement in the Swift 5 timeframe.

3 Likes

Would this use @dynamicMemberLookup from SE-0195?

Edit: Should the proposed x, y, z, w properties and init(x:y:z:w:) be removed?

1 Like

x, y, z, w is the 99.9% case; it's probably best to expose other labels via a wrapper if someone wants to use them.

6 Likes

We can use dynamicMemberLookup with some @semantics tricks to get ".xxyy" sorts of accessors to work in the future without huge overload sets, but that is a cleanly separable project for the future.

5 Likes

CGFloat in particular can, because it is maintained by people who know about the hidden protocol requirements. What about my own wrappers? e.g.

struct Distance {
  var meters: Double
  var kilometers: Double { return meters/1000 } // etc
}

How would I make this type vectorisable without using hidden requirements? An extra level of indirection allows any user code to point to an underlying stdlib type which conforms.

The "hidden" protocol requirements are public, so this wouldn't stop you, but FWIW they've been "unhidden" in the proposal, anyway. They are now SIMD2Storage, etc.

2 Likes

Hi everyone,

The core team discussed the latest revision and has accepted the proposal.

Note that this acceptance includes some changes to the naming of the types that was brought up during the discussion, but that may elicit more feedback now they are the final recommendation. Given the timing of the Swift 5 release, the core team has agreed to go ahead and merge the implementation as accepted for now. However, since the naming of these types has been the focus of much of the review thread, I am going to leave the review thread open for some further feedback on the naming.

Thanks!
Ben

4 Likes

I think the names SIMD4 are strictly worse than the names Vector4, and I’m actually quite surprised that the core team would recommend this.

Instead of using the common mathematical term, it uses a niche computing term that describes semantics/implementation. Anybody with at least high school knowledge of math knows what a vector is. Much fewer people know what SIMD is.

I have yet to see a compelling argument for why the standard vector types in Swift should not have SIMD semantics. It seems to me that if you want to do vector arithmetic (most commonly in 2, 3 or 4 dimensions) these are the types you should use. And even if there are use cases where someone doesn’t want their vectors or matrices to be SIMD, should that really penalize the common case? That seems unprecedented in Swift naming, and definitely not in line with progressive disclosure.

I think this naming will have a very real effect: these types will be used less. People will not reach for them even when they should, because the names look daunting and strange.

7 Likes

I haven't participated in this review, but I'm no expert in SIMD and skimming the thread gave me the impression it was headed in a good direction so I left it alone. But now I feel something went wrong with the naming.

Removing "vector" from the name is a big mistake in my view.

If you look at the Wikipedia article on SIMD, vectors aren't even mentioned in the summary at the top. It's all general concepts of how computers parallelize data processing. Are people really expected to understand that SIMD4, which stands for "Single Instruction Multiple Data 4", is some kind of vector? That is pretty confused as a type name. One could even reasonably see the 4 as a version number (as in HTML5, SSE3, GCC4) or part of the acronym (as in UTF8, AMD64).

Is there a reason I'm missing why those types aren't a good enough base currency for mathematical vector types? I think it'll be sad when people fail to realize there are vector types available and instead build their own custom types or use tuples because "SIMD" is a weird name that means nothing to them. Also, if Swift is to have a type allowing library APIs to transact in vectors without having to each define their own custom type, I think it ought to have a better name than that.

8 Likes

Doc comments on these initializers mentioned the scalarCount property. It's an instance property -- how can an initializer depend on it (even in comments)?

Why not define an additional static scalarCount?

  /// Initialize from array literal
  ///
  /// Precondition: the array must have exactly scalarCount elements.
  init(arrayLiteral elements: Scalar...)
  
  /// Initialize from sequence
  ///
  /// Precondition: the sequence must have exactly scalarCount elements.
  init<S: Sequence>(_ elements: S) where S.Element == Scalar
2 Likes

The implementation first uses self.init() to create a vector with zero in all lanes. Then it copies scalars from the sequence, and checks if there have been too many/few elements. It can already access self.scalarCount at this point.

1 Like

There isn't a single major reason, but there are a few factors that mean we might want to consider something else for this purpose down the road. The biggest consideration is that the SIMD types support a pile of operations that abstract mathematical vectors do not. Mathematical vectors cannot be multiplied (and when they can, it's isn't necessarily pointwise), don't have a notion of lane-wise comparisons, etc. More generally, they may not even be finite-dimensional or have a notion of "components" with integer indices (though obviously, 2, 3, and 4-element vectors do).

These operations are generally useful, so even if use cases do not require them, having them is usually not harmful. But they do give some reason for pause.

Personally, I'm basically neutral on the subject. I think that either naming works fine semantically, and there are some nice things about both names. Ultimately, I don't think that it will matter that much (anecdotally, we've been using the convention simd_float4 and simd::float4 in the Obj-C and C++ SDK on Apple platforms for a few years[†], and we're not aware of lots of people being confused by the names there).

[†] originally these types were spelled vector_float4 and matrix_float4x4 in [Obj-]C. Having the uniform prefix simd_ was eventually judged to be a bigger win than spelling out matrix and vector, so they were renamed.

7 Likes

It doesn't seem to be necessary for anything, but it can always be added later.

The implementation is not what the user sees, however.

@scanon The shorter names of concrete types (e.g. SIMD64<T>) are good, but I wonder if the SIMD protocol should be renamed? Especially if there will be another protocol for matrices?

  • protocol SIMDScalar
  • protocol SIMDVector
  • protocol SIMDMatrix
1 Like

@benrimmington It's a fair question, but I think that either naming works fine, and one of them has already been approved.

The above makes a lot more sense to me than the (afaics) currently implied:

  • protocol SIMDScalar
  • protocol SIMD
  • protocol SIMDMatrix

I don't see how leaving out the "Vector"-part works fine in this (future) context.

1 Like

"SIMD" means that operations apply uniformly to all lanes. A SIMD matrix type would also be a SIMD vector.