empty intervals Alex Shinn (21 Apr 2022 11:02 UTC)
Re: empty intervals Bradley Lucier (21 Apr 2022 16:30 UTC)
Re: empty intervals Bradley Lucier (21 Apr 2022 16:37 UTC)
Re: empty intervals Per Bothner (21 Apr 2022 19:23 UTC)
Re: empty intervals Bradley Lucier (21 Apr 2022 21:59 UTC)
Re: empty intervals Per Bothner (21 Apr 2022 22:11 UTC)
Re: empty intervals Bradley Lucier (23 Apr 2022 17:56 UTC)
Re: empty intervals Per Bothner (23 Apr 2022 19:44 UTC)
Re: empty intervals Alex Shinn (24 Apr 2022 05:03 UTC)
Re: empty intervals John Cowan (21 Apr 2022 22:56 UTC)
Re: empty intervals Alex Shinn (22 Apr 2022 09:03 UTC)

Re: empty intervals Bradley Lucier 21 Apr 2022 21:59 UTC

Per:

I looked again a bit at SRFI 164.  Thanks for reminding me of it.

This SRFI has a routine make-specialized-array-from-data, which allows
one to treat some one-dimensional objects (vectors and homogeneous
vectors) as arrays.

(This reminds me that right now we do not have a string-storage-class,
or perhaps this would be better names as character-storage-class,
because my limited understanding is that a string is not always simply a
concatenated list of characters.)

If this SRFI were to be extended to incorporate zero-dimensional arrays
or arrays with length zero axes, then each routine would need to be
carefully examined to determine what the semantics would be on these
"new" objects.

Or at least that is what I, personally, would require.

The rest of this email tries to go through such a thought process with
the array-squeeze example I gave above.  The first part is pretty
coherent, then later it loses focus.

In my thoughts on the matter, zero-dimensional arrays that contain a
single element, a box, as you say, makes more sense to me than arrays
that have zero-length axes.  To be honest, I cannot see how SRFI 164
deals with array-ref with arrays some of whose axes have length zero.

The following discussion speculates about what array-curry should do in
such special cases.

Brad

So, for example, the general case of the array-squeeze I gave above has
the formula (*):

            (car (array->list
                  (array-curry   ;; this array has only one element.
                   (array-permute a permutation)
                   (- dim (length ks)))))))))

where ks is the list of axes of a of length 1, permutation is a
permutation that reorders the list of axes to place length-one axes first.

The two special cases are when all axes have length 1, or when no axes
have length 1, in which cases the second argument to array-curry has
values 0 and dimension of a, respectively, both cases that are not
currently allowed.

If we were to allow (*) to work when no axes have length 1, then

(array-curry a (array-dimension a))

should return an array of dimension 0, which contains the original array
a, and array->list applied to that zero-dimensional array should return
a length-one list containing a, and the car of that list will be a.

If we were to allow (*) to work when all axes have length 1 (so a has a
single element), then

(array-curry a 0)

should return an array with that single element; the dimension doesn't
matter if all we're going to do with the result is

(car (array->list (array-curry a 0)))

So should (array-curry a 0) return a itself for all a, even those with
more than one element?  This would make (*) work.

Actually, for array-curry, this might not be a terrible idea so far:

(a) (array-curry a (array-dimension a)) => zero-dimension array containing a

(b) (array-curry a 0) => a

Or because (array-curry A k) returns an array whose elements are arrays.
should (array-curry a 0) return a new array where every element of a is
wrapped in a new zero-dimensional array?  Which properties are we going
to insist are consistent?

Now let's start thinking about arrays with domains that are zero-length
in some dimension.

So at least one direction k of the domain will not have length 1, so the
(array-curry a 0) case (b) will be avoided.

If none of the axes has length 1 then case (a) will be invoked, so again
array-curry will return a zero-dimensional array containing a,
array->list will return a one-element list with a as the only element,
and car will return the original array.

Seems to make sense.

Let's assume now that at least one axis of a has length 1.  Then those
axes will be reordered to be at the front, array-curry will return a
usual-type array all of whose axes will have dimension 1, the single
element of which will be an array with at least one axis length 0.

Again, seems to make some sense, in that it seems self-consistent so far.

====================================

Now I think: what if we move all the length-zero axes to the front,
instead of the length-one axes to the front, and then call array-curry
on the resulting array.  In other words, what does

(array-curry a (- (array-dimension a) 1))

return if the first dimension has length zero?  If you follow the
general formula, it should return a length 0 array, each element of
which is an array with domain consisting of the remaining axes in order.

A length-zero array has no elements.

It would seem that a length-zero array should have a getter that just
raises an error.  So

(define B (array-curry (make-array (make-interval '#(0 1))) 1))

should return an array that

(array-ref B i) => error

and

(define B (array-curry (make-array (make-interval '#(1 0))) 1))

returns an array such that

(array-ref B 0) => an empty array

and

(array-ref (array-ref B 0) i) => error

It seems to be a question of at which point the error is raised in the
curried result.

=================================

And now, if functionally an array with at least one axis of length zero has

(array-ref a i j k l)

raise an error no matter the number or values of the arguments, is there
a difference between empty arrays of different dimensions?