- array-outer-product op array1 array2procedure
Implements the outer product of array1 and array2 with the operator op, similar to the APL function with the same name.
Assume that array1 and array2 are arrays and that op is a function of two arguments. Assume that (list-tail l n) returns the list remaining after the first n items of the list l have been removed, and (list-take l n) returns a new list consisting of the first n items of the list l. Then array-outer-product returns the immutable array
(make-array (interval-cartesian-product (array-domain array1) (array-domain array2)) (lambda args (op (apply (array-getter array1) (list-take args (array-dimension array1))) (apply (array-getter array2) (list-tail args (array-dimension array1))))))
This operation can be considered a partial inverse to array-curry. It is an error if the arguments do not satisfy these assumptions.
Note: You can see from the above definition that if C is (array-outer-product op A B), then each call to (array-getter C) will call op as well as (array-getter A) and (array-getter B). This implies that if all elements of C are eventually accessed, then (array-getter A) will be called (array-volume B) times; similarly (array-getter B) will be called (array-volume A) times.
This implies that if (array-getter A) is expensive to compute (for example, if it's returning an array, as does array-curry) then the elements of A should be pre-computed if necessary and stored in a specialized array, typically using array-copy, before that specialized array is passed as an argument to array-outer-product. In the examples below, the code for Gaussian elimination applies array-outer-product to shared specialized arrays, which are of course themselves specialized arrays; the code for matrix multiplication and inner-product applies array-outer-product to curried arrays, so we apply array-copy to the arguments before passage to array-outer-product.