Implications of array broadcasting Bradley Lucier (24 Oct 2024 18:55 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(28 Oct 2024 06:17 UTC)
|
Re: Implications of array broadcasting
Bradley Lucier
(30 Oct 2024 23:57 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(31 Oct 2024 13:15 UTC)
|
Re: Implications of array broadcasting
Bradley Lucier
(02 Nov 2024 04:24 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(03 Nov 2024 22:21 UTC)
|
Re: Implications of array broadcasting
Bradley Lucier
(05 Nov 2024 03:08 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(07 Nov 2024 00:27 UTC)
|
Re: Implications of array broadcasting
Bradley Lucier
(07 Nov 2024 20:29 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(08 Nov 2024 00:01 UTC)
|
Re: Implications of array broadcasting
Bradley Lucier
(08 Nov 2024 20:51 UTC)
|
Re: Implications of array broadcasting
Alex Shinn
(08 Nov 2024 22:54 UTC)
|
I've been thinking about how array broadcasting in the Python sense could be added to this library. This issue clarified some thoughts, which I'd like to summarize here (mainly so I can stop thinking about them for a while). 1. Broadcasting is a non-1-1 transformation on arrays (for nontrivial broadcasts). In general, the example of broadcasting shows that non-1-1 transforms can be useful, so this statement in the SRFI: ================ We also require that our affine maps be one-to-one, so that if i⃗ ≠j⃗ then T(i⃗ )≠T(j⃗ ). Without this property, modifying the i⃗ th component of A would cause the j⃗ th component to change. ================ should be loosened. Note that the justification of one-to-one maps is array mutation, so non-1-1 maps should be allowed for immutable arrays. 2. Because an array's setter is reified, so that it can be stored in variables, etc., the procedure array-freeze! in general is meaningless---any existing reference to the setter is unmodified. So I think array-freeze! should be removed. 3. The specification of array->list says ================ It is guaranteed that (array-getter array) is called precisely once for each multi-index in (array-domain array) in lexicographical order. ================ I specified it this way so that one could rely on array->list, array-copy, etc., to "do the right thing" on generalized arrays whose getters have intrinsic side effects. A big example for me is generalized arrays that read successive elements from a file when converted to a list or copied to a specialized array. However, if such a generalized array is nontrivially broadcast before being copied, then copying the broadcast result will cause the getter of the original array to be called multiple times for each original index, which can obviously cause trouble when reading from a file, etc. So I think broadcasting should be limited to specialized arrays, in the same way that "sharing" arrays using an arbitrary affine transform is limited to specialized arrays. So it should be specialized-array-broadcast, with nontrivial broadcasts limited to immutable arrays. In this way we can implement array broadcasting without array copying, which is the correct way to do it in my opinion. In contrast, the NumPy manual says =============== However, there are cases when broadcasting uses unnecessarily large amounts of memory for a particular algorithm. =============== I don't know whether this means that NumPy sometimes allocates memory for the results of array broadcasting, but I don't want to do that. 4. For practical reasons, broadcasting should be limited to arrays with zero lower bounds. Chibi has the routine array-to-origin, which translates a given array to have all zero lower bounds. It's useful, it should be added (even though it's "just" another convenience procedure). 5. If the transform passed to specialized-array-share is not one-to-one, then one should require that the array argument to specialized-array-share be immutable. Over the past few weeks I've been looking for algorithms to determine whether an affine map on an interval of multi-indices (in the SRFI 231 sense) is one-to-one. The specified interval is an important part of this question. For example, if A is the matrix (10 1) and the interval is (0,100]\times[0,8), then the mapping x->Ax is one-to-one on that interval, even though A is not one-to-one on all pairs of integers (or on $R^2$, either). I've reduced the problem (perhaps incorrectly) to an integer quadratic programming problem with linear constraints, which appears in general to be NP-hard. The derivation is attached as a PDF file. So if that's true, it's not something you'd add to error checking in specialized-array-share. In the special case of array broadcasting, one can easily determine whether the broadcast is nontrivial (increasing the width of an interval axis), so one knows to check whether the associated array argument is immutable. But in general it seems difficult to check. (Although I'd love to be proved wrong.) So the specification of specialized-array-share should say something like: ================= It is an error if the transform argument is not one-to-one on the new-domain argument. ================= (I understand that the trend is to say "Program behavior is undefined if ...", but the rest of the document stays "It is an error if ...") 7. The document discussing how to test whether an integer-valued affine mapping is one-to-one on a specified interval is attached below. Brad