From: Tamas Papp
Subject: map with multiple values
Date: 
Message-ID: <878x66olok.fsf@pu100877.student.princeton.edu>
Hi,

Suppose I have a vector, and I want to apply a function that returns
multiple values to each element and get the result as a matrix.  Eg a
hypothetical

(map-values #'round #(1.4 1.7)

would return

#2A((1 0.4) (2 -0.3))

(errors in floating point arithmetic disregarded).

My messy solution currently uses multiple-value-list to capture the
returned values as a list, then extract elements from this list, which
are copied to rows of a matrix.  I wonder if there is something more
elegant.

Thanks,

Tamas

From: ········@yahoo.es
Subject: Re: map with multiple values
Date: 
Message-ID: <1192305252.733147.199030@e9g2000prf.googlegroups.com>
On 13 oct, 21:32, Tamas Papp <······@gmail.com> wrote:
> Hi,
>
> Suppose I have a vector, and I want to apply a function that returns
> multiple values to each element and get the result as a matrix.  Eg a
> hypothetical
>
> (map-values #'round #(1.4 1.7)
>
> would return
>
> #2A((1 0.4) (2 -0.3))
>
> (errors in floating point arithmetic disregarded).
>
> My messy solution currently uses multiple-value-list to capture the
> returned values as a list, then extract elements from this list, which
> are copied to rows of a matrix.  I wonder if there is something more
> elegant.
>
> Thanks,
>
> Tamas

What about coerce?
From: ········@yahoo.es
Subject: Re: map with multiple values
Date: 
Message-ID: <1192307817.690115.205900@i38g2000prf.googlegroups.com>
On 13 oct, 21:54, ········@yahoo.es wrote:
> On 13 oct, 21:32, Tamas Papp <······@gmail.com> wrote:
>
>
>
> > Hi,
>
> > Suppose I have a vector, and I want to apply a function that returns
> > multiple values to each element and get the result as a matrix.  Eg a
> > hypothetical
>
> > (map-values #'round #(1.4 1.7)
>
> > would return
>
> > #2A((1 0.4) (2 -0.3))
>
> > (errors in floating point arithmetic disregarded).
>
> > My messy solution currently uses multiple-value-list to capture the
> > returned values as a list, then extract elements from this list, which
> > are copied to rows of a matrix.  I wonder if there is something more
> > elegant.
>
> > Thanks,
>
> > Tamas
>

 This is just an idea:

 (defun map-values (f l)
                   (let (ll)
                     (setq ll (map 'list (lambda(x)(multiple-value-
list (funcall f x))) l))
                     (make-array (list (length (car ll)) (length
ll)) :initial-contents ll)))


 (map-values #'round #(1.8 2.5))   =>     #2A((2 -0.20000005) (2 0.5))
From: Tamas Papp
Subject: Re: map with multiple values
Date: 
Message-ID: <874pguodz4.fsf@pu100877.student.princeton.edu>
········@yahoo.es writes:

> On 13 oct, 21:54, ········@yahoo.es wrote:
>> On 13 oct, 21:32, Tamas Papp <······@gmail.com> wrote:
>>
>>
>>
>> > Hi,
>>
>> > Suppose I have a vector, and I want to apply a function that returns
>> > multiple values to each element and get the result as a matrix.  Eg a
>> > hypothetical
>>
>> > (map-values #'round #(1.4 1.7)
>>
>> > would return
>>
>> > #2A((1 0.4) (2 -0.3))
>>
>> > (errors in floating point arithmetic disregarded).
>>
>> > My messy solution currently uses multiple-value-list to capture the
>> > returned values as a list, then extract elements from this list, which
>> > are copied to rows of a matrix.  I wonder if there is something more
>> > elegant.
>>
>> > Thanks,
>>
>> > Tamas
>>
>
>  This is just an idea:
>
>  (defun map-values (f l)
>                    (let (ll)
>                      (setq ll (map 'list (lambda(x)(multiple-value-
> list (funcall f x))) l))
>                      (make-array (list (length (car ll)) (length
> ll)) :initial-contents ll)))
>
>
>  (map-values #'round #(1.8 2.5))   =>     #2A((2 -0.20000005) (2 0.5))

Thanks.  It seems that I can't escape conversion into a list, so I
will just work with that.

Tamas
From: David Golden
Subject: Re: map with multiple values
Date: 
Message-ID: <DVcQi.22578$j7.427875@news.indigo.ie>
Tamas Papp wrote:


> Thanks.  It seems that I can't escape conversion into a list, so I
> will just work with that.
>

If you want a /gloriously imperative/ solution:

(defun map-2mvret (f invec)
           (let* ((rowcount (array-dimension invec 0))
                  (outmat (make-array `(,rowcount 2) :element-type 'float)))
             (loop for i below rowcount 
                  do (setf (values (aref outmat i 0)
                                   (aref outmat i 1))
                           (funcall f (aref invec i))))
             outmat))

(map-2mvret #'round #(1.8 2.5 5.3 7.2))
=> #2A((2 -0.20000005) (2 0.5) (5 0.3000002) (7 0.19999981))

Anyway, I thought it a good opportunity to point out
(setf (values ...) ...)  which simplifies a lot of mv code:
http://www.lispworks.com/documentation/HyperSpec/Body/05_abc.htm
From: Andrew Philpot
Subject: Re: map with multiple values
Date: 
Message-ID: <slrnfh39uu.9pa.philpot@ubirr.isi.edu>
On 2007-10-13, Tamas Papp <······@gmail.com> wrote:
> ········@yahoo.es writes:
>
>> On 13 oct, 21:54, ········@yahoo.es wrote:
>>> On 13 oct, 21:32, Tamas Papp <······@gmail.com> wrote:
>>>
>>>
>>>
>>> > Hi,
>>>
>>> > Suppose I have a vector, and I want to apply a function that returns
>>> > multiple values to each element and get the result as a matrix.  Eg a
>>> > hypothetical
>>>
>>> > (map-values #'round #(1.4 1.7)
>>>
>>> > would return
>>>
>>> > #2A((1 0.4) (2 -0.3))
>>>
>>> > (errors in floating point arithmetic disregarded).
>>>
>>> > My messy solution currently uses multiple-value-list to capture the
>>> > returned values as a list, then extract elements from this list, which
>>> > are copied to rows of a matrix.  I wonder if there is something more
>>> > elegant.
>>>
>>> > Thanks,
>>>
>>> > Tamas

If you can live with a vector of vectors instead of a true 2D matrix,
perhaps this is acceptable.  It never creates the intermediate list to
populate the vector.  Maybe some compilers could avoid consing the
rest list in some circumstances (is memory efficiency an issue for you
here?)

;;; result is vector of vectors

(defun map-to-vector-of-vectors (f sequence)
  (map 'vector #'(lambda (x)
		   (multiple-value-call #'vector 
		     (funcall f x)))
       sequence))

Alternatively, if you are sure that the function F will always
generate (say) only two values, you could preallocate the matrix and
just write to it as you go.  No explicit initial-contents list; not
much chance of a compiler open-coding one's way around the rest list
alloc cost.

;;; requires that you know up upfront the output size

(defun map-to-predictable-matrix (f sequence &key (columns 2))
  (let* ((rows (length sequence))
	 (m (make-array (list rows columns)))
	 (r 0))
    
    (flet ((populate-row (&rest values)
	     ;; add new row
             ;; something like REPLACE would be nice here
	     (loop for value in values
		 as j from 0 by 1
	       ;; deposit the value
		 do (setf (aref m r j) value))
	     (incf r)))

      (map nil #'(lambda (x)
		   (multiple-value-call #'populate-row
		     (funcall f x)))
	   sequence)
      m))
  )

;;; Finally, try to grow each row as needed, which might incur lots of
;;; memory alloc costs, especially if F returns different numbers of
;;; values for different inputs.

;;; spreads across rows

(defun map-to-matrix (f sequence)
  (let ((m (make-array '(0 0)))
	(r 0))
    (flet ((fill-new-row (&rest values)
	     ;; add space for new row (maxcols in size)
	     (setq m (adjust-array m (list (1+ r) (array-dimension m 1))))
	     (loop for value in values
		 as j from 0 by 1
	       ;; incrementally make this row large enough
		 when (> (1+ j) (array-dimension m 1))
		 do (setq m (adjust-array m (list (1+ r) (1+ j))))
	       ;; deposit the value
		 do (setf (aref m r j) value))
	     (incf r)))

      (map nil #'(lambda (x)
		   (multiple-value-call #'fill-new-row 
		     (funcall f x)))
	   sequence)
      m))
  )

On toy examples, the memory patterns of all three of these seemed
similar (ACL8.0, linux).

-- 
Andrew Philpot
USC Information Sciences Institute
·······@isi.edu
From: D Herring
Subject: Re: map with multiple values
Date: 
Message-ID: <0YOdnaIcGq5AxIzanZ2dnUVZ_jmdnZ2d@comcast.com>
Tamas Papp wrote:
> Suppose I have a vector, and I want to apply a function that returns
> multiple values to each element and get the result as a matrix.  Eg a
> hypothetical
> 
> (map-values #'round #(1.4 1.7)
> 
> would return
> 
> #2A((1 0.4) (2 -0.3))
> 
> (errors in floating point arithmetic disregarded).
> 
> My messy solution currently uses multiple-value-list to capture the
> returned values as a list, then extract elements from this list, which
> are copied to rows of a matrix.

Your solution looks something like this?
(defun vmap (vec f n)
   (let ((answer (make-array (list (length vec) n))))
     (dotimes (m (length vec))
       (let ((val (multiple-value-list (funcall f (aref vec m)))))
	(loop for el in val
	      for i from 0 below n
	      do (setf (aref answer m i) el))))
     answer))

CL-USER> (vmap #(1.2 3.4) 'round 2)
#2A((1 0.20000005) (3 0.4000001))


As an alternative, you could use displaced arrays and pass them to 
your functions...  but I'm not sure it looks any better:

(defun vmap2 (vec f n)
   (let ((array (make-array (list (length vec) n))))
     (dotimes (m (length vec))
       (let ((slice (make-array (list n)
			       :displaced-to array
			       :displaced-index-offset (* m n))))
	(funcall f (aref vec m) slice)))
     array))

(defun f2 (x vec)
   (setf (aref vec 0) x
	(aref vec 1) (* x x)))

(vmap2 #(1 2 3 4) 'f2 2)


- Daniel
From: Carl Taylor
Subject: Re: map with multiple values
Date: 
Message-ID: <qccQi.675162$p47.109005@bgtnsc04-news.ops.worldnet.att.net>
Tamas Papp wrote:
> Hi,
> 
> Suppose I have a vector, and I want to apply a function that returns
> multiple values to each element and get the result as a matrix.  Eg a
> hypothetical
> 
> (map-values #'round #(1.4 1.7)
> 
> would return
> 
> #2A((1 0.4) (2 -0.3))


Multiple-value-call is your new Lisp friend.

CL-USER 19 > 
(make-array '(2 2) :element-type 'float
                   :initial-contents
                     (map 'vector
                             #'(lambda (f)
                                   (multiple-value-call #'vector (round f)))
                             #(1.4 1.7)))


#2A((1 0.39999998) (2 -0.29999995))


Carl Taylor