Re: Last call for comments on SRFI 179: Nonempty Intervals and Generalized Arrays (Updated) Bradley Lucier 03 May 2020 02:56 UTC

On 5/2/20 8:37 PM, John Cowan wrote:
> Outer product is straightforward: the dimensions of the outer product of
> A and B are the concatenation of the dimensions of A with the dimensions
> of B, and you basically multiply (in the sense of a group operation)
> each element of A and each element of B to produce the corresponding
> element of the result.
> Inner product is more complex: the last dimension of A must be equal to
> the last dimension of B, and both are omitted from the dimensions of the
> result. Thus in one dimension the vectors must be equal in size and the
> result is the scalar dot product.  Similarly, the inner product of two
> matrices is just ordinary matrix multiplication: multiplying an a x b
> matrix by a b x c matrix gives an a x c result.  Naturally addition and
> multiplication are arbitrary n-ary and binary functions.
> But I do not understand how this generalizes to higher dimensional
> arrays.  The APL standard can be found at
> <>. This
> is not actually a PDF, it's a gzipped pdf, so you have to download it,
> rename it to is13751.pdf.gz, and then use gunzip to get the actual PDF.
> The formal definition of inner product is found on p. 121 (physical PDF
> p. 135), but the examples on the next page do not extend to the third
> dimension.  I hope someone can make more sense of them than I can.   The
> definitions of various terms can be found in pp. 18-24 (physical PDF pp.
> 32-38).

My apologies for my misunderstanding.

It would seem that you'd already have to know APL to understand the
definition of inner product from that document.

I found

which at least has an explanation in words.  Using SRFI 179, I think
this is the correct definition

(define (inner-product A f g B)
    (lambda (a b)
      (array-reduce f (array-map g a b)))
    (array-curry A 1)
    (array-curry (array-rotate B 1) 1)))

(define TABLE1
    '(1 2
      5 4
      3 0)
    (make-interval '#(3 2))))

(define TABLE2
    '(6 2 3 4
      7  0  1  8)
    (make-interval '#(2 4))))

(define (array-display A)
   (array-for-each (lambda (row)
                     (array-for-each (lambda (col)
                                       (display col) (display #\space))
                   (array-curry A 1))

(array-display (inner-product TABLE1 + * TABLE2))

which gives

20 2 5 20
58 10 19 52
18 6 9 12

as expected.

APL seems to pun 1 x 1 arrays with scalar values (both ways), and SRFI
179 does not do that, so it's not terribly easy to reproduce the other
example on that page.  But one can calculate the other example as

(define X
   (list->specialized-array '(1 3 5 7) (make-interval '#(4))))

(define Y
   (list->specialized-array '(2 3 6 7) (make-interval '#(4))))

(array-reduce + (array-map (lambda (x y) (if (= x y) 1 0)) X Y))

and you get 2, as expected.  (The last expression is pulled out from the
definition of inner-product.)

I didn't want to define inner-product in the SRFI because of this lack
of punning---a mathematical inner product of two vectors could not be
computed with the SRFI "inner-product" if it were defined as above.  In
the matrix multiply example in the document I call it dot-product, and
it does produce a scalar value.

Should I give the above definition as another example?  (It took me at
least 20 minutes to figure it out, so perhaps I should ;-)