chapel-lang / chapel

a Productive Parallel Programming Language
https://chapel-lang.org
Other
1.78k stars 418 forks source link

should there be an operator for matrix multiplication? #16721

Open mppf opened 3 years ago

mppf commented 3 years ago

Today in the LinearAlgebra module we write matrix-matrix multiplication with e.g. A.dot(B) or dot(A,B).

However, it would be more math-like if we had an infix operator for this.

It's my understanding that Python uses @ for this and Julia uses * for mat-mat and .* for element-wise.

Should we add an operator for matrix multiplication? If so, what should it be?

mppf commented 3 years ago

Related to #14282 is the idea that we could use a UTF-8 symbol such as

ben-albrecht commented 3 years ago

Ignoring whether or not it's a good idea, is it possible for the language syntax & parser to support . as a matrix-multiplication operator?

var C = A . B;
mppf commented 3 years ago

I doubt it, because there would be an ambiguity between matrix multiplication and method call. Eg

var C = some kind of matrix thing;
var isdiagonal = some kind of matrix thing;
C . isdiagonal // does this call an isdiagonal paren-less method? Or multiply with the local variable?
e-kayrakli commented 3 years ago

Related to #14282 is the idea that we could use a UTF-8 symbol such as •

Even though people seem to like unicode operators in Julia, I downvoted this as I need someone to train me how that would be a good idea while typing code. I definitely don't want to type latex in my code :) I wonder what some of the (potential) LinearAlgebra users think about this.

How common is element-wise multiplication in linear algebra? My thinking is that not as common as matrix multiplication, so maybe we need * to do matrix multiplication and handle element-wise via a method on matrices. This would make * behave differently between 2D arrays and matrices, however.

mppf commented 3 years ago

FWIW I brought up this question because I was thinking about how a Matrix type was a motivating example for user-defined implicit conversions. One of the things we might get from a Matrix type (separate from 2D arrays) would be for * to mean matrix-matrix multiplications but this issue brings up an alternative strategy to that. (I currently do not think it makes sense to have implicit conversions between any new Matrix type and 2D arrays - such implicit conversions are particularly problematic for matrix types like DiagonalMatrix or TriangularMatrix).

bradcray commented 3 years ago

My preference here would be to distinguish matrices from 2D arrays and use * for matrix multiplication rather than introducing a new operator and conflating matrices and 2D arrays (in saying that, I realize they're fairly conflated today).

(I'm also generally open to the more concept we've discussed at times of permitting users to define any operators they want using identifiers that are sequences of certain symbolic characters, where doing so would permit supporting a new operator as matrix multiplication. But not to the extent that it suggests conflating 2D arrays and matrices; I'd only do this if, for some reason, we didn't want * on a matrix type to mean multiplication).

damianmoz commented 3 years ago

Not a big fan of UTF-8 operators because it is too easy to confuse with a similar looking symbol depending on your font. When I looked at @mppf 's first comment about UTF-8, it still looked like a dot to me. When I now look at it on a nice big 27inch screen, it looks more like a tiny bullet symbol. No, I do not need glasses.

The words used above. "This would make * behave differently between 2D arrays and matrices, however" should ring alarm bells. Allowing the same symbol to behave differently on a type which is nominally a superset of another is a recipe for disaster. On a totally different type, not an issue (in general).

I have never understood why we do not label what we commonly call matrix multiplication a "Binet product" after the French guy who first described it (although he is remembered in the Cauchy-Binet formula). But that has nothing to do with Chapel! I would like to ensure that '*' (ASCII 0x2a) always means element-by-element (or Hadamard or Schur) multiplication wherever it is used.

ghbrown commented 1 year ago

I think having * be type dependent would make things harder, and I do prefer it as the elementwise operator. For what it's worth * ambiguity is apparently exactly why Python introduced the @ operator (which I like, for what it's worth).

Having never used them, I'm still strongly against unicode stuff. I find plain text plenty expressive for coding in every other language, and it makes some other aspects of development a bit easier.

I don't mind the current .dot() notation. Sure it's more than one character, but not many and it's plain text.

If there is a nice character or scheme for making it a single character I'd be interested, but the current situation is just fine by me.

mppf commented 4 months ago

It's currently the case that @ is used for attributes as in @chpldoc.nodoc proc foo() { }. It's currently the case that you can also write @ chpldoc.nodoc proc foo() { } but I don't think that's helpful and I'd like to propose requiring no space there. We already require no space for a type query formal as in proc f(arg: ?t) -- it cannot be proc f(arg: ? t). Making this change would allow us to introduce @ in general as an operator which could be used for matrix multiplication.

mppf commented 4 months ago

I've created #25020 to propose not allowing space after @ for attributes.

mppf commented 4 months ago

If we follow #25020 to make @ usable as an operator, we still have a challenge in how to parse A@B. Perhaps we could insist it be written A @ B. Or, perhaps there is a way to adjust the parser to handle this case (maybe it could assume such a case can't be an attribute because it's mid-expression? details might be tricky)

bradcray commented 4 months ago

Turning to the top-level question:

I don't think we should have the Chapel language define an operator for matrix multiplication, or to support matrix multiplication as a language-level feature (specifically, we're not a Linear Algebra language, and if the language were to support a matrix-multiplication op, it's easy to imagine wanting other Linear Algebra operators like "solve" as well).

That said, I'm much more comfortable interpreting this question as "Should it be possible for a module to define a matrix multiplication / solve / arbitrary operator?", either by adding additional operators into the language that a module could choose to overload for those purposes, or by supporting a general operator-definition syntax in which users can write various forms of:

operator [symbolic / non-alphanumeric identifier] { … }

E.g., in such a world, I'm imagining that the lexer would create an "operator identifier" token (e.g., TOPIDENT) and parse that in operator declaration contexts and infix contexts (and potentially prefix/postfix, with more work).

mppf commented 4 months ago

That said, I'm much more comfortable interpreting this question as "Should it be possible for a module to define a matrix multiplication / solve / arbitrary operator?"

Right, I think that's what we're talking about here. IMO this issue is mainly about the LinearAlgebra module. It's true that there's some discussion of adding operators to the language, but IMO that'd just be allowing some more patterns as operators (e.g @ or .* or whatever) and then using operator @ (or whatever) definitions in the LinearAlgebra module to use them.

Supposing that, or your generalized operator concept, what operator specifically would we want the LinearAlgebra module to use for matrix multiplication?

ghbrown commented 4 months ago

I think @ is simple and familiar enough to Python/numpy users to be a solid contender. A second option (if viable) could be # which evokes "matrix multiplication" to me. But I'm remembering # does have a use in Chapel, but perhaps it could still work.