;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PART-MATRIX takes a matrix in list of lists form ;; returns a list of four matrics ;; For example if the matrix passed in was ;; ( 1 2 3 4 5 6 ;; 1 2 3 4 5 6 ;; 1 2 3 4 5 6 ;; a b c d e f ;; a b c d e f ;; a b c d e f ) ;; PART-MATRIX will return: ;; ( 1 2 3 ( 4 5 6 ;; x11 = 1 2 3 , x12 = 4 5 6 ;; 1 2 3 ) 4 5 6 ) ;; ;; ( a b c ( d e f ;; x21 = a b c , x22 = d e f ;; a b c ) d e f ) ;; returns a list of (x11 x12 x21 x22) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun part-matrix (m) (let* ((n (length m)) (k (/ n 2)) r1 r2 r3 r4 ;r1, r2, r3, r4 are the four smaller matrices f-half ;top half of matrix s-half) ;bottom half of matrix (cond ((< n 1) (ERROR "PART-MATRIX takes a matrix of min size 2x2.")) ;if the nxn matrix with n not even number ;partition the matrix such that x11 would be (n-1)/2 ;hence x22 would be (n+1)/2 ((not (integerp k)) (progn (setq k (floor k)) (setq f-half (dotimes (i k f-half) (setq f-half (append f-half (list (pop m)))))) (setq s-half m) (setq r1 (first-half f-half k)) (setq r2 (second-half f-half k (- n k))) (setq r3 (first-half s-half k)) (setq r4 (second-half s-half k (- n k))) (list r1 r2 r3 r4))) ;if nxn matrix with n even number (T (progn (setq f-half (dotimes (i k f-half) (setq f-half (append f-half (list (pop m)))))) (setq s-half m) (setq r1 (first-half f-half k)) (setq r2 (second-half f-half k k)) (setq r3 (first-half s-half k)) (setq r4 (second-half s-half k k)) (list r1 r2 r3 r4)))))) ;handles left half of matrix (defun first-half (fm k) (mapcar #'(lambda (x) (let (y) (dotimes (i k y) (setq y (append y (list (pop x))))))) fm)) ;handles right half of matrix (defun second-half (sm s k) (mapcar #'(lambda (x) (let (y) (dotimes (i k y) (setq y (append y (list (elt x (+ i s)))))))) sm)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; CON-MATRIX takes four matrices as inputs ;; returns a bigger matrix formed by these matrices ;; such that M = ( m11 m12 ;; m21 m22) ;; For example: ;; (con-matrix '((1 2) (3 4)) '((a b) (c d)) '((5 6) (7 8)) '((e f) (g h))) ;; ==> '((1 2 a b) (3 4 c d) (5 6 e f) (7 8 g h)) ;; Because: ;; if m11 = (1 2 m12 = (a b m21 = (5 6 m22 = (e f ;; 3 4) , c d), 7 8), g h) ;; then M = (m11 m12 = (1 2 a b ;; m21 m22) 3 4 c d ;; 5 6 e f ;; 7 8 g h) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun con-matrix (m11 m12 m21 m22) (cond ;check if the matrices have the right dimensions ((/= (num_row m11) (num_row m12)) (format NIL "Number of rows in ~a and ~a do not agree." m11 m12)) ((/= (num_row m21) (num_row m22)) (format NIL "Number of rows in ~a and ~a do not agree." m21 m22)) ((/= (num_col m11) (num_col m21)) (format NIL "Number of columns in ~a and ~a do not agree." m11 m21)) ((/= (num_col m12) (num_col m22)) (format NIL "Number of columns in ~a and ~a do not agree." m12 m22)) ;put the four matrices together (T (append (mapcar #'(lambda (a b) (append a b)) m11 m12) (mapcar #'(lambda (a b) (append a b)) m21 m22))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MPROD will take one or more matrices ;; MPROD will return the product ;; if there is one ;; else PROD will return an ERROR ;; ;; For example: ;; (mprod '((1 2) (3 4)) '((1 0) (0 1))) ;; ==> ((1 2) (3 4)) ;; because ( 1 2 * ( 1 0 = ( 1 2 ;; 3 4 ) 0 1 ) 3 4 ) ;; ;; (mprod '((1 2 3) (4 5 6)) '((1 2) (3 4) (5 6))) ;; ==> '((22 28) (49 64)) ;; because ( 1 2 ;; ( 1 2 3 * 3 4 = ( 22 28 ;; 4 5 6 ) 5 6 ) 49 64 ) ;; (mprod '((1 0) (0 1))) ;; ==> '((1 0) (0 1)) ;; ;; (mprod '((1 2) (3 4)) '((1 0) (0 1)) '((1 0) (0 1))) ;; ==> '((1 2) (3 4)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun mprod (x &rest y) (cond ;base case return x ((NULL y) x) ((not (matrix? x)) (format NIL "~a is not a valid Matrix." x)) ((not (matrix? (car y))) (format NIL "~a is not a valid Matrix." (car y))) ((/= (num_col x) (num_row (car y))) (format NIL "Number of columns of ~a and number of rows of ~a do not match." x (car y))) ;allows PROD to take any number of matrices as args (T (apply #'mprod (mapcar #'(lambda (a) (prod-row a (car y))) x) (cdr y))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; PROD-ROW takes one row of the first matrix and the second matrix ;; PROD-ROW returns a row of results ;; For example: ;; if r = (1 2 3) and y = (1 2 ;; 3 4 ;; 5 6), ;; then (PROD-ROW r y) ==> '(22 28) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun prod-row (r y) (let (a b) (dotimes (j (length (car y)) a) (setq b 0) (setq a (append a (list (dotimes (i (length r) b) (setq b (+ b (* (elt r i) (elt (elt y i) j))))))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MADD takes one or more matrices as input ;; all such matrices must be the same size ;; MADD returns the sum of all input matrices ;; For example: ;; (madd '((1 2 3) (4 5 6))) ;; ==> '((1 2 3) (4 5 6)) ;; ;; (madd '((1 2) (3 4)) '((1 2) (3 4)) '((5 6) (7 8))) ;; ==> '((7 10) (13 16)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun madd (x &rest y) (cond ;base case ((NULL y) x) ;check if the matrices have the same dimensions ((/= (num_row x) (num_row (car y))) (format NIL "Number of rows of ~a and ~a do not match." x (car y))) ((/= (num_col x) (num_col (car y))) (format NIL "Number of columns of ~a and ~a do not match." x (car y))) ;recursive on the cdr of the second input ;this way MADD can accept more than two inputs (T (apply #'madd (mapcar #'(lambda (a b) (add-row a b)) x (car y)) (cdr y))))) ;; ADD-ROW is a helper function for MADD ;; ADD-ROW takes two rows and return their sum (defun add-row (xr yr) (mapcar #'(lambda (a b) (+ a b)) xr yr)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MSUB takes one or more matrices as input ;; all such matrices must be the same size ;; MSUB subtracts the first two matrices then the next ;; if the input is one matrix, it will be the return value ;; For example: ;; (msub '((1 2 3) (4 5 6))) ;; ==> '((1 2 3) (4 5 6)) ;; ;; (msub '((1 2) (3 4)) '((1 2) (3 4)) '((5 6) (7 8))) ;; ==> '((-5 -6) (-7 -8)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun msub (x &rest y) (cond ;base case ((NULL y) x) ;check if the dimensions of the matrices match ((/= (num_row x) (num_row (car y))) (format NIL "Number of rows of ~a and ~a do not match." x (car y))) ((/= (num_col x) (num_col (car y))) (format NIL "Number of columns of ~a and ~a do not match." x (car y))) ;recursive on the cdr of the secon input ;so that MSUB can accept more than two inputs (T (apply #'msub (mapcar #'(lambda (a b) (sub-row a b)) x (car y)) (cdr y))))) ;; SUB-ROW is a helper function for MSUB ;; SUB-ROW returns the difference of the two input rows (defun sub-row (xr yr) (mapcar #'(lambda (a b) (- a b)) xr yr)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; MNEG takes a matrix ;; returns the negative of the matrix ;; For example: ;; (mneg '((1 -2) (0 3.5))) ;; ==> '((-1 2) (0 -3.5)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun mneg (x) (mapcar #'(lambda (a) (mapcar #'- a)) x)) ;; MINVERSE (defun minverse (m) (list (list (/ 1 (caar m))))) ;; GEN0 ;; returns a nxn 0 matrix (defun gen0 (n m) (let (c r) (dotimes (i n c) (dotimes (j m r) (setq r (append r (list 0)))) (setq c (append c (list r))) (setq r 'nil)))) ;; NUM_COL returns the number of columns in matrix x (defun num_col (x) (length (car x))) ;; NUM_ROW returns the number of rows in matrix x (defun num_row (x) (length x)) ;; MATRIX? returns T if x is a matrix, else return NIL (defun Matrix? (x) (if (= 1 (length (remove-duplicates (mapcar #'length x)))) T NIL))