From: Joseph Oswald
Subject: APL-like operators defined in Lisp?
Date: 
Message-ID: <6itu7q$3lh$1@news.fas.harvard.edu>
Hi there.

  I'm interested in doing some manipulations on multi-dimensional arrays
of numbers, typically uniform in type, and typically floating-point.

  A typical operation would be, given a (n  x ... x 2 m x p x ...) array
of floats, to return a (n x .... x m x p x ...) array of complex numbers, 
where the real and imaginary parts were in consecutive locations along the
m axis.

  Coincidentally, I've been reading about APL, which seems to be designed
particularly to do these kinds of tricks. However, APL has some drawbacks

  1) no good, free implementation for Power Macintosh

  2) yet another notation and language to learn
    2a) unusual notation for common things like negative numbers, 
    2b) everything associates to the *right*
    2c) funky greek letters everywhere
    2d) hard to integrate to other stuff

  3) doesn't have all the power for abstraction of Common Lisp
    3a) although newer dialects (e.g. 'J') may have improved on this
    
  4) Just isn't Lisp!!!

Does anyone know if there is a good library of APL-like routines for Lisp,
that allow the same kind of array-manipulation power? 

---Joe


P.S.  Some examples to illustrate the kinds of tricks I want to play.

  I wrote a function to do my first manipulation:

  (array-condense #'complex 2 *array*  j 'single-float)

  where 2 is the "condense factor", i.e., the number of arguments for
#'complex, j is an integer indicating which dimension to 'condense'. 
'single-float is the optional indication of the element-type of the new
array.

  Another thing I've done is write a macro

  (with-array-iteration elem *array* (*i foo bar *q)
    (setf (aref *dest-array* i q) (+ elem 3.0)))

  which expands to code which loops i and q through the corresponding
array dimensions, and elem is a symbol macro which effectively expands to
(aref *array* i foo bar q), so that, in this case, all the elements at
y=foo, z=bar, get copied to a *dest-array* after being incremented by 3.0.

From: Johann Hibschman
Subject: Re: APL-like operators defined in Lisp?
Date: 
Message-ID: <mtiungvb6w.fsf@physics.berkeley.edu>
········@login1.fas.harvard.edu (Joseph Oswald) writes:

>   I'm interested in doing some manipulations on multi-dimensional arrays
> of numbers, typically uniform in type, and typically floating-point.

[ snip ]

>   Coincidentally, I've been reading about APL, which seems to be designed
> particularly to do these kinds of tricks. However, APL has some drawbacks

I'm not familiar with APL, but I'm interested in getting a good
array-manipulation package working in Common Lisp.  I don't know of
any good packages, so I'm trying to design one myself.  (In, of
course, my Copious Free Time.)

So, what do you like about APL's syntax?  How would they write these
problems?  I'm only familiar with IDL.

For example, I'm thinking about:

  1) Automatic array rank promotions.  What do you get when you add a
scalar to a vector, or a vector to an array?  Most packages seem to
just duplicate the lower-dimensional item along the "missing axis."
Does APL do this?

  2) Slices, perhaps with strides.  I'd like to be able to write
       (array-setf (slice x 0 '(3 7) '(0 4))  ; x is 3rd rank 
	           (identity-matrix 4))       ; 4x4 identity matrix

  3) Logical ops.
     ;; set all elemnts of x which are < 0.0 to 0.0
     (array-setf (where x #'(lambda (y) (< y 0.0)))
                 0.0)

So what am I missing?  I'm sure the APL folks have thought a lot about
these issues, so I'd like to tap their knowledge, but I don't really
have the time to learn all of APL right now.

Does anyone have any other syntax suggestions?

- Johann
From: Marco Antoniotti
Subject: Re: APL-like operators defined in Lisp?
Date: 
Message-ID: <lw67jfmki4.fsf@galvani.parades.rm.cnr.it>
How about the following little function

(defun iota (n)
  (labels ((do-iota (m)
              (if (zerop m)
                  (list 0)
                  (cons m (do-iota (1- m)))
              )))
    (nreverse (do-iota n))))

:)

With IOTA

(defun factorial (n) (reduce #'* (rest (iota n)) :initial-value 1))

Of course using the SERIES package buys you more. :)
             
-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - (0)6 - 68 80 79 23, fax. +39 - (0)6 - 68 80 79 26
http://www.parades.rm.cnr.it
From: Raymond Toy
Subject: Re: APL-like operators defined in Lisp?
Date: 
Message-ID: <4nu36vfx6n.fsf@rtp.ericsson.se>
Marco Antoniotti <·······@galvani.parades.rm.cnr.it> writes:

> How about the following little function
> 
> (defun iota (n)
>   (labels ((do-iota (m)
>               (if (zerop m)
>                   (list 0)
>                   (cons m (do-iota (1- m)))
>               )))
>     (nreverse (do-iota n))))
> 
> :)
> 
> With IOTA
> 
> (defun factorial (n) (reduce #'* (rest (iota n)) :initial-value 1))
> 
> Of course using the SERIES package buys you more. :)
>              

Here is a simple series version of the same set of functions:

(defun iota (n)
  (declare (fixnum n)
	   (optimizable-series-function 1))
  (scan-range :upto n :type 'fixnum))


(defun factorial (n)
  (collect-fn 'integer #'(lambda () 1) #'* (subseries (iota n) 1)))

This is slightly different from the above in that iota returns a
series, not a list, of the integers from 0 to n.

The nice apart about using series, is that the factorial function
expands into

(COMMON-LISP:LET ((#:C-817 0) (#:INDEX-822 0) (#:NUMBERS-823 0) #:OUT-825)
  (DECLARE (TYPE FIXNUM #:NUMBERS-823)
           (TYPE FIXNUM #:INDEX-822)
           (TYPE INTEGER #:C-817))
  (SETQ #:OUT-825 N)
  (SETQ #:NUMBERS-823 (- 0 1))
  (SETQ #:INDEX-822 (- -1 1))
  (SETQ #:C-817 ((LAMBDA () 1)))
  (TAGBODY
   #:LL-827
    (SETQ #:NUMBERS-823 (+ #:NUMBERS-823 1))
    (IF (> #:NUMBERS-823 #:OUT-825) (GO SERIES::END))
    (INCF #:INDEX-822)
    (IF (MINUSP #:INDEX-822) (GO #:LL-827))
    (SETQ #:C-817 (* #:C-817 #:NUMBERS-823))
    (GO #:LL-827)
   SERIES::END)
  #:C-817)

which is about what you'd write for an iterative factorial function.

Ray
From: Joseph Oswald
Subject: Re: APL-like operators defined in Lisp?
Date: 
Message-ID: <6ja7vv$kab$1@news.fas.harvard.edu>
In article <··············@rtp.ericsson.se>,
Raymond Toy  <···@rtp.ericsson.se> wrote:

>Marco Antoniotti <·······@galvani.parades.rm.cnr.it> writes:
>
>> How about the following little function
>> 
   [list-based "iota" omitted]

>> (defun factorial (n) (reduce #'* (rest (iota n)) :initial-value 1))


Toy writes:
>Here is a simple series version of the same set of functions:
>
>(defun iota (n)
>  (declare (fixnum n)
>	   (optimizable-series-function 1))
>  (scan-range :upto n :type 'fixnum))
>
>
>(defun factorial (n)
>  (collect-fn 'integer #'(lambda () 1) #'* (subseries (iota n) 1)))
>
>This is slightly different from the above in that iota returns a
>series, not a list, of the integers from 0 to n.
 
 [expansion of series macros omitted]
>
>which is about what you'd write for an iterative factorial function.


  Does the series approach generalize to multi-dimensional arrays? My
understanding is that the series approach works only for 1-d sequences,
although it potentially has lazy evaluation [??].

  I was thinking purely of an array approach:

(defun index (n)
  "Unary APL iota, generates a vector containing numbers 1..n"

  ;; in real APL, this would take account of the current state of
  ;; the array-origin environment variable

  (let ((arr (make-array n :element-type 'double-float)))
    (dotimes (i n)
      (setf (aref arr i) (1+ i)))))

Then, using "apl:acc" to implement "/" accumulation on arrays of arbitrary
rank.

(defun factorial (n)
  (apl:acc #'* (index n)))

  Not knowing much APL except what I have read in books, I think a lot of
its power comes from very flexible indexing of arrays, filtering arrays
based on computed "boolean" arrays, and its ability to combine scalars and
arrays in a very flexible way. Somewhat analogous to Lisp's native ability
to create, map over, and filter lists or trees.

  One problem of implementing some of the APL things in Lisp is
recognizing some of the optimizations that an APL interpreter might make.
The series approach, I gather, is pretty efficient for sequences. I don't
know if a real APL interpreter would perform {times}/{iota}n without
allocating all the storage for the iota array. I'm not sure it really
would matter in this case, unless APL numbers typically have some huge
dynamic range: n!  is liable to overflow a reasonable range of float for a
quite small value of n. My HP calculator gives 253! = 5.17e499. Allocating
an intermedicate array of 253 numbers is not outrageous.

  A more likely problem is that of selecting members out of a large array
by some "sparse" criterion. Naive APL would create an equally large array
of zeroes, sparsely populated by 1s for those members satisfying the
criterion, iterate over this sparse array looking for 1s and accumulating
the corresponding elements of the original array, then dispose of the huge
0/1 array. Whereas a more efficient technique might be to recognize the
selection idiom, and to the test-and-accumulate without the intervening
boolean array.

  I think what I will do, I guess in traditional Lisp fashion, is
implement as much of APL as I feel like, in a naive formulation, then take
a look at how "series" or other embedded languages go about making some of
these things space/time efficient. 

--Joe
From: Raymond Toy
Subject: Re: APL-like operators defined in Lisp?
Date: 
Message-ID: <355AFBCD.B73BD988@rtp.ericsson.se>
Joseph Oswald wrote:
> 
>   Does the series approach generalize to multi-dimensional arrays? My
> understanding is that the series approach works only for 1-d sequences,
> although it potentially has lazy evaluation [??].

I think series is basically 1-d, so unless your multi-dimensional array
can 
be processed in a 1-d fashion, you can't use series.

Series does give you lazy evaluation.

Ray