Pretty sure Numpy’s einsum[1] function allows all of this reasoning in vanilla numpy (albeit with a different interface that I assume this author likes less than theirs). Quite sure that first example of how annoying numpy can be could be written much simpler with einsum. [1]: https://numpy.org/doc/stable/reference/generated/numpy.einsu...
The author posted a previous article about why they don't like numpy and his problems with einsum: https://dynomight.net/numpy/
DumPy: NumPy except it's OK if you're dum
51–60 of 62 posts
Re: DumPy: NumPy except it's OK if you're dum
#52Re: DumPy: NumPy except it's OK if you're dum
#53Earlier quoted context omitted.
Implicir means write once easy, debug, extend, read hard.
It also means that you don't have to reimplement the same things all over again when your dimensions change.
Re: DumPy: NumPy except it's OK if you're dum
#54Earlier quoted context omitted.
Why do you need to invert a matrix?
It's what the "first example of how annoying numpy can be" does, using either np.linalg.solve in a loop or a cursed multidimensional index rearrangement.
The code could be just:
AiX = np.linalg.solve(A, X[:, np.newaxis, :, np.newaxis]).squeeze()
Z = np.vecdot(Y, AiX)
Or if you don't like NumPy 2.0: AiX = np.linalg.solve(A, X[:, np.newaxis, :])
Z = np.einsum("jk,ijk->ij", Y, AiX)
The NumPy 1.x code is very intuitive, you have A[i, j, n] and X[i, n] and you want to use the same X[i] for all A[i, j], so just add an axis in the middle. Broadcast, which the author very strongly refuse to understand, deals with all the messy parts.Alternatively, if you hate `[:, np.newaxis, :]` syntax, you may do:
I, J, K, K = A.shape
AiX = np.linalg.solve(A, X.reshape(I, 1, K, 1)).squeeze()
Z = np.vecdot(Y, AiX)
I can read this faster than nested for-loops. YMMV.Re: DumPy: NumPy except it's OK if you're dum
#55But the proposal is very questionable. I like loops instead of broadcast (apply_...), but making them this kind of black magic just adds equal amount of mental load.
As for compiled languages - they do optimize for SIMD, if you're ok running on CPU. Optimizing for CUDA and GPU parallelization... that's quite a niche demand, I think, to justify inconveniences for the more common users.
Re: DumPy: NumPy except it's OK if you're dum
#56Re: DumPy: NumPy except it's OK if you're dum
#57Re: DumPy: NumPy except it's OK if you're dum
#58I’ve known some people who didn’t want to learn the syntax of numpy and did it all in loops, and the code was not easy to read. It was harder to read. The fundamental issue is that operations on high dimensional arrays are very difficult to reason about. Numpy can probably be improved, but I don’t think loops are the answer.
The point here is not that it’s loops per se, the point is that the indexing is explicit. It seems like a big win to me. The article’s ~10 non-trivial examples all make the code easier to read, and more importantly, to understand exactly what the code is doing. It is true that some operations are difficult to reason about, that’s where explicit indexing really helps. The article resonates with me because I do want to…
For transposes, np.einsum can be easier to read as it let's you use (single character, admittedly) axis specifiers to "name" them.
Re: DumPy: NumPy except it's OK if you're dum
#59Re: DumPy: NumPy except it's OK if you're dum
#60> So, I removed it. In DumPy you can only do AB if one of A or B is scalar or A and B have exactly the same shape. That’s it, anything else raises an error. Instead, use indices, so it’s clear what you’re doing.
I also dislike the seemingly inconsistent adding of last axes with length 1.
I do like the capability that existing axes of length 1 will be broadcasted to any length of the other array in the operation, and use that all the time.
If I understand the text correctly, the author removed that as well.