re: matrix operations

  • Follow


Barry Margolin wrote:

> Zachary Turner <ztur...@bindview.com> wrote: 
> >I've got a 3x3 matrix, stored as ((r1c1 r1c2 r1c3) (r2c1 r2c2 r2c3) (r3c1 
> >r3c2 r3c3)).  I want to check if any of the columns have the same three 
> >elements.  It's easy for rows, I can just use 
> >(or 
> >   (every #'equal (car matrix)) 
> >   (every #'equal (cadr matrix)) 
> >   (every #'equal (caddr matrix))) 
> 
> Actually, that doesn't work.  EVERY passes a single element to the test 
> function, but EQUAL requires two arguments.  What you need is: 
> 
> (or (every #'(lambda (x) (equal x (caar matrix))) 
>            (cdar matrix)) 
>     (every #'(lambda (x) (equal x (caadr matrix))) 
>            (cdadr matrix)) 
>     (every #'(lambda (x) (equal x (caaddr matrix))) 
>            (cdaddr matrix))) 

That's hideous.

> 
> >My questions are: 
> >a) Can I do this more elegantly using a mapxxx function? 
> 
> (defun (all-elements-equal (list) 
>   (destructuring-bind (head . tail) list 
>     (every #'(lambda (x) (equal x head)) 
>            tail)))) 

Racket:

(define (all-elements-equal elements)
  (define head (first elements))
  (andmap (curry equal? head) (rest elements)))


> 
> (defun any-rows-equal (matrix) 
>   (any #'all-elements-equal matrix)) 


(define (any-row-uniform matrix)
  (ormap all-elements-equal matrix))


> 
> >b) How can I check columns using one of the map functions?  It seems like 
> >there should be a way using mapcar since it pulls elements from each list 
> >and applies a function to each of them, but I don't know how to or the 
> >results together.  Or maybe there's even a better way that I'm not aware of. 
> 
> Well, here's a solution similar to my first rewrite: 
> 
> (or (every #'(lambda (x) (equal x (caar matrix))) 
>            (mapcar #'car (cdr matrix))) 
>     (every #'(lambda (x) (equal x (cadar matrix))) 
>            (mapcar #'cadr (cdr matrix))) 
>     (every #'(lambda (x) (equal x (caddar matrix))) 
>            (mapcar #'caddr (cdr matrix))))


(define (any-column-uniform matrix)
  (apply ormap (compose all-elements-equal list) matrix))
0
Reply w_a_x_man (2778) 6/1/2012 4:16:05 AM

Why so complicates?
CL-USER> (defparameter matr1 #(#(1 2 3) #(2 3 4) #(5 6 7)))
MATR1
CL-USER> (defparameter matr2 #(#(1 2 3) #(2 3 4) #(5 6 7)))
MATR2
CL-USER> (equalp matr1 matr2)
T
CL-USER> (defparameter matr2 #(#(1 2 3) #(2 3 4) #(5 6 8)))
MATR2
CL-USER> (equalp matr1 matr2)
NIL


On 06/01/2012 06:16 AM, WJ wrote:
> Barry Margolin wrote:
>
>> Zachary Turner<ztur...@bindview.com>  wrote:
>>> I've got a 3x3 matrix, stored as ((r1c1 r1c2 r1c3) (r2c1 r2c2 r2c3) (r3c1
>>> r3c2 r3c3)).  I want to check if any of the columns have the same three
>>> elements.  It's easy for rows, I can just use
>>> (or
>>>    (every #'equal (car matrix))
>>>    (every #'equal (cadr matrix))
>>>    (every #'equal (caddr matrix)))
>>
>> Actually, that doesn't work.  EVERY passes a single element to the test
>> function, but EQUAL requires two arguments.  What you need is:
>>
>> (or (every #'(lambda (x) (equal x (caar matrix)))
>>             (cdar matrix))
>>      (every #'(lambda (x) (equal x (caadr matrix)))
>>             (cdadr matrix))
>>      (every #'(lambda (x) (equal x (caaddr matrix)))
>>             (cdaddr matrix)))
>
> That's hideous.
>
>>
>>> My questions are:
>>> a) Can I do this more elegantly using a mapxxx function?
>>
>> (defun (all-elements-equal (list)
>>    (destructuring-bind (head . tail) list
>>      (every #'(lambda (x) (equal x head))
>>             tail))))
>
> Racket:
>
> (define (all-elements-equal elements)
>    (define head (first elements))
>    (andmap (curry equal? head) (rest elements)))
>
>
>>
>> (defun any-rows-equal (matrix)
>>    (any #'all-elements-equal matrix))
>
>
> (define (any-row-uniform matrix)
>    (ormap all-elements-equal matrix))
>
>
>>
>>> b) How can I check columns using one of the map functions?  It seems like
>>> there should be a way using mapcar since it pulls elements from each list
>>> and applies a function to each of them, but I don't know how to or the
>>> results together.  Or maybe there's even a better way that I'm not aware of.
>>
>> Well, here's a solution similar to my first rewrite:
>>
>> (or (every #'(lambda (x) (equal x (caar matrix)))
>>             (mapcar #'car (cdr matrix)))
>>      (every #'(lambda (x) (equal x (cadar matrix)))
>>             (mapcar #'cadr (cdr matrix)))
>>      (every #'(lambda (x) (equal x (caddar matrix)))
>>             (mapcar #'caddr (cdr matrix))))
>
>
> (define (any-column-uniform matrix)
>    (apply ormap (compose all-elements-equal list) matrix))

0
Reply jpthing (785) 6/8/2012 9:24:42 PM


John Thingstad <jpthing@online.no> writes:

> Why so complicates?
> CL-USER> (defparameter matr1 #(#(1 2 3) #(2 3 4) #(5 6 7)))
> MATR1
> CL-USER> (defparameter matr2 #(#(1 2 3) #(2 3 4) #(5 6 7)))
> MATR2
> CL-USER> (equalp matr1 matr2)
> T
> CL-USER> (defparameter matr2 #(#(1 2 3) #(2 3 4) #(5 6 8)))
> MATR2
> CL-USER> (equalp matr1 matr2)
> NIL

The OP asked for 3x3 matrices, not for vectors of vectors.  
This is not C!

Those variables are special but you didn't earmuff them.


(defparameter *mat1* #2A((1 2 3) (4 5 6) (7 8 9)))
(defparameter *mat2* #2A((1 2 3) (4 5 6) (7 8 9)))
(equalp *mat1* *mat2*) --> T


Now, as for why one would want to write his own matrix equal operator:

(defparameter *mat1* #2A((#\D #\A) ("N" "G") (1.0 2.0))
(defparameter *mat2* #2A((#\D #\A) ("N" "G") (1   2))
(defparameter *mat3* #2A((#\d #\a) ("n" "g") (1.0 2))

(equalp *mat1* *mat2*) --> T
(equalp *mat1* *mat3*) --> T    ; !
(equal  *mat1* *mat2*) --> NIL  ; !
(equal  *mat1* *mat3*) --> NIL



(defun array-equal-p (a1 a2)
  "RETURN: A1 and A2 have the same dimensions and their elements in the
same position are equal."
  (and (equal (array-dimensions a1) (array-dimensions a2))
       (loop
          :for i :below (array-total-size a1)
          :always (if (and (numberp (row-major-aref a1 i)) (numberp (row-major-aref a2 i)))
                    (=     (row-major-aref a1 i) (row-major-aref a2 i))
                    (equal (row-major-aref a1 i) (row-major-aref a2 i))))))

(array-equal-p *mat1* *mat2*) --> T
(array-equal-p *mat1* *mat3*) --> NIL

Notice it also works on tensors, and other higher dimensions arrays:

(array-equal-p #3A(((1 2)     (3 4)) (("five" "six") (7 9)))
               #3A(((1.0 2.0) (3 4)) (("five" "six") (7 9)))) --> T



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.
0
Reply pjb (7645) 6/9/2012 1:33:08 AM

2 Replies
31 Views

(page loaded in 0.064 seconds)


Reply: