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
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?
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))
········@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
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
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
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
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