7 ms·
PEP 465 – Dedicated infix operators for matrix multiplication and matrix power
- captaincrowbar 13y agoI'm kind of baffled by this. Python has operator overloading, so what's wrong with using * for matrix multiplication? I know there's a bit in the PEP that claims to answer this, but I can't understand their argument. Can someone explain?
- gradys 13y agoIt looks like it says there are enough cases where libraries crave two multiplication operators, elementwise multiplication and matrix multiplication, that it makes sense to add an operator to the language.
- bsaul 13y agoWould matrix multiplicqtion be useful for anything other than matrices ? I can understand to provide an operator in the language when it's usable by many types, but i don't understand what sense would it have to create an operator just for one type... Even more so when that type isn't part of the language. Or does it mean that @ would be used just for arrays, and that it would be useful for cases when arrays aren't matrices of numbers ?
- aaren 13y agoIt does away with the need for a separate matrix type. When you are using numpy (most imported non stdlib library according to the pep!) and you have two arrays a and b, a * b is elementwise multiplication. numpy currently has a matrix type. When a and b are both matrices, a * b is matrix multiplication. The @ operator would do away with the need for a matrix type. Then, a * b is element wise and a @ b is matrix wise, and a and b are always the same type. This would simplify numpy and lots of things that are based on it.
- bsaul 13y ago"The @ operator would do away for a matrix type" which is only an issue because every lib needs to define its own matrix type ? Then why isn't the solution to provide this type in the standard lib ?
- shoyer 13y agoGuido has indicated that he is ready to accept the PEP after a few details are worked out: https://groups.google.com/forum/#!msg/python-ideas/aHVlL6BADLY/GBCTSbY40QQJ https://groups.google.com/forum/#!msg/python-ideas/aHVlL6BAD... So it appears that we will indeed have @ for matrix multiplication in Python 3.5! This is a feature the numeric python computing has been hoping for for a long, long time.
- Malarkey73 13y agoThat's funny. If there is one thing that Python users do more after than diss R - it's steal from R.
- scardine 13y agoImmature computer language designers borrow; mature designers steal.
- teddyh 13y agoI have not witnessed this behavior, but it would be perfectly logical to dismiss R while absorbing its features – R is a domain-specific language (statistics) while Python is a general purpose programming language. A GP language will always have a larger useful scope than a DSL.
- maxerickson 13y agoCalling R a DSL is like insisting that Python is just a scripting language.
- teddyh 13y agoR is “for statistical computing and graphics”¹. 1) http://www.r-project.org/ http://www.r-project.org/
- maxerickson 13y agoSure, the facilities for statistics and plotting are well exposed. But all the features you need for 'general purpose' are in there too, and they aren't awkward to access (at least, relative to anything else).
- synparb 13y agoA %*% B != A @ B
- GFK_of_xmaspast 13y ago
- krallja 13y agoGreat! Minor quibble: the underlying method names should not mention `mat` (e.g. `__matmul__`); instead mentioning the shape of the operator (e.g. `__atmul__`).
- ekimekim 13y agoThis. It allows for the general meaning to be conveyed (it's numeric, kind of multiplicative, uses @ symbol) without restricting it to a particular use case. This allows other users to define their own meanings for @ in a variety of contexts. We could even have a reverse mnemonic: AlTernate Multiplication
- shoo 13y agothat might be a good idea, or a little strange. many existing python infix boolean operators resolve to method names based on the meaning, rather than the symbol. e.g. `a + b` resolves to `a.__add__(b)` rather than `a.__plus__(b)`, `x * * y` resolves to `x.__pow__(y)` rather than `x.__asteriskasterisk__(y)`, say. so arguably it would be consistent to name @ after the common meaning also. http://docs.python.org/2/reference/datamodel.html#emulating-numeric-types http://docs.python.org/2/reference/datamodel.html#emulating-... on the other hand, "consistency is not necessarily a virtue: one can be consistently obnoxious" - C.A.B. Smith that said, i like the idea that @ should be more general than just for matrices. an arbitrary infix boolean operation, neither necessarily commutative nor invertible. even when talking about matrix multiplication, generalising slightly from arrays to abstract elements of vector spaces, and from matrices to linear transformations between vector spaces leaves you writing the same kinds of expressions that compose linear transformations without anything necessarily being represented as a matrix.
- valtron 13y agoIf you're really determined, you can use `.` as an operator via __getattr__ and inspect :p
- shoo 13y agough. very loosely related, this reminds me of calling R functions from python that take keyword arguments with dots in their names. >>> f(hello.world=123) File "<stdin>", line 1 SyntaxError: keyword can't be an expression so instead: >>> f(**{'hello.world':123})
- jey 13y agoHuh? Isn't it a question of whether you are doing matrix or array ops, so the type system is the issue? I have rarely needed to do elementwide multiply on matrices, and if I do, in Eigenproblem I can just call mat.array() to get an ArrayView. Really, the problem is that NumPy is a crappily designed library primarily intended for array ops, and is just not well suited for linear algebra.
- hdevalence 13y agoThis is addressed in the proposal: Use a second type that defines __mul__ as matrix multiplication: As discussed above (Background: What's wrong with the status quo?), this has been tried this for many years via the numpy.matrix type (and its predecessors in Numeric and numarray). The result is a strong consensus among both numpy developers and developers of downstream packages that numpy.matrix should essentially never be used, because of the problems caused by having conflicting duck types for arrays. (Of course one could then argue we should only define __mul__ to be matrix multiplication, but then we'd have the same problem with elementwise multiplication.) There have been several pushes to remove numpy.matrix entirely; the only counter-arguments have come from educators who find that its problems are outweighed by the need to provide a simple and clear mapping between mathematical notation and code for novices (see Transparent syntax is especially crucial for non-expert programmers). But, of course, starting out newbies with a dispreferred syntax and then expecting them to transition later causes its own problems. The two-type solution is worse than the disease.
- justincormack 13y agoIndeed, especially as the functions that are + and * can vary based on type too, as you can have them defined over any ring.
- rspeer 13y ago> NumPy is a crappily designed library I don't think you know what you're talking about.
- jey 13y agoTry Eigen, you'll agree that NumPy is an array library that had linear algebra support thrown in as an afterthought.
- zmmmmm 13y agoCoincidentally I just implemented this the other day for a quick Matrix class in Groovy. Was about 4 lines of code.
- pekk 13y agoWho else uses @ this way? It seems really ad hoc and ugly as a core feature of Python syntax
- ryansouza 13y agoSeems to me that Haskell's ability to infix named functions is a much nicer solution over-all
- pcarbonn 13y agoI agree. I wish python had the capability to infix functions. Maybe the topic for a new PEP ?
- akehrer 13y agoThis is this[1] workaround. I wonder if a whole set of infix matrix operations could be added to reduce the need to load numpy for simple tasks. A @* B A @. B A @+ B [1] http://code.activestate.com/recipes/384122/ http://code.activestate.com/recipes/384122/
- pcarbonn 13y agoYes, but making it part of the language would bring clear error messages in case of misuse, and would allow the use of a different token, e.g. ":", as in smalltalk
- stormbrew 13y agoIt kind of seems to me that it's actually vectored multiplication that's the odd one out that should maybe have a special syntax, maybe even one that applies to many operations and not just multiplication. A matrix is a Thing that happens to also be a collection. A vector you want to multiply is just a collection. Really vector multiplication is just a map operation, so make some syntactic sugar to generate an operator comprehension: a = [1,2,3] b = [4,5,6] c = a [*] b # or something # becomes c = [x * y for (x,y) in zip(a,b)] # or c = a.__vecmul__(b) This would make more sense to me.
- scotty79 13y agoThis looks bad: S = (H.dot(beta) - r).T.dot(inv(H.dot(V).dot(H.T))).dot(H.dot(beta) - r) but this: S = (( (H) .dot (beta) - (r) ).T) .dot (inv( (H) .dot (V) .dot ((H).T) )) .dot ( (H) .dot (beta) - (r) ) is close enough to: S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r) although bit less readable due to being bit longer.
- gamegoblin 13y agoI'd really like to see user-defined infix operators such as those in Haskell. There are some baked into the standard library (*+-/ etc), but you can also roll your own, so people could make do until this gets accepted.
- maxerickson 13y agoYou can get cute about it: http://code.activestate.com/recipes/384122-infix-operators/ http://code.activestate.com/recipes/384122-infix-operators/ The code there overrides | to construct arbitrary operators that are used by wrapping an object in |, like: a |x| b where x defines the custom behavior.
- RhysU 13y agoThe bloody associativity issue is unresolved...? Of course it should be right associative. Otherwise ABx means (AB)x which is idiotic for numerical work. One would have to write A(Bx) to get reasonable performance which isn't far enough away from A.dot(B.dot(x)) to justify the implementation overhead. Lastly, as awful as it sounds, it is nice when awfully expensive things like 10K by 10K matmats have some visual weight. It makes people think about how they're written down.
- caretcaret 13y agoWhy not overload the already-defined * * ? Matrix multiplication is used much more than matrix exponentation (which can be delegated to methods), and * * is already right associative.
- shoyer 13y agoBecause already means element-wise power. The reason we need a new operator (@) for matrix multiplication is precisely so we can all the same operators for arrays that we already use for scalars.