[swift-evolution] Basic element-wise operator set for Arrays, Arrays of Arrays, etc.

Stephen Canon scanon at apple.com
Fri Feb 17 13:25:42 CST 2017

> On Feb 17, 2017, at 10:51 AM, Xiaodi Wu via swift-evolution <swift-evolution at swift.org> wrote:
> There's nothing, afaik, which stands in the way of that syntax today. The proposal is to extend the standard library to add syntax for a math library. The idea of having a core math library has already been mentioned on this list, to great approval, but it should come in the form of an actual library, and not a syntax only!

Right. IMO the way to do this is to develop such a library outside of the stdlib to the point that it’s useful enough to be employed for real work and people can evaluate what works and what doesn’t. That may require small language and stdlib changes for support, which should be brought-up here.

Once such a library were reasonably mature, it would be reasonable to propose it for inclusion in swift proper. I expect this process will take a couple *years*.

FWIW, I personally despise MATLAB .operator notation, though I accept that it’s pretty much achieved saturation at this point. It looks reasonably nice for simple single-operand expressions, but it imposes a large burden on the compiler (and often leads to inefficient code). In this regard, they are something of an attractive nuisance. Consider your example:

	3.0 .* A .* B ./ (C.^ 4.0)

with the most obvious implementation, this generates four calls to vector functions:

	- multiply array by scalar (tmp0 <— 3 .* A)
	- elementwise multiplication (tmp1 <— tmp0 .* B)
	- elementwise exponentiation (tmp2 <— C .^ 4)
	- elementwise division (result <— tmp1 ./ tmp2)

again, with the obvious implementation, this wastes space for temporaries and results in extraneous passes through the data. It is often *possible* to solve these issues (at least for some the most common cases) by producing proxy objects that can fuse loops, but that gets very messy very fast, and it’s ton of work to support all the interesting cases.

On the other hand, the stupid obvious loop:

	for i in 0 ..< count {
		result[i] = 3*A[i]*B[i]/(C[i]*C[i]*C[i]*C[i])

or the cleaner, with a little sugar:
	zip3(A,B,C).map { 3 * $0.0 * $0.1 / ($0.2 ^ 4) }

requires a tiny bit of boilerplate, but only a single pass through the data and allows the compiler to vectorize. Even if the four vector functions use by the .operations are perfectly hand-optimized, the multiple passes and extra memory traffic they entail often makes it *slower* than the stupid for loop.

I don’t mean to be too discouraging; all of these issues are surmountable, but I (personally) think there’s a lot of development that should happen *outside* of the stdlib before such a feature is considered for inclusion in the stdlib.

– Steve
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170217/c3f1fc25/attachment.html>

More information about the swift-evolution mailing list