1 ;;; -*- Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;;; The data in this file contains enhancments. ;;;;;
5 ;;; Copyright (c) 1984,1987 by William Schelter,University of Texas ;;;;;
6 ;;; All rights reserved ;;;;;
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; (c) Copyright 1982 Massachusetts Institute of Technology ;;;
9 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 (macsyma-module matrix
)
15 (declare-top (special *ech
* *tri
* *inv
*
16 mdl $detout vlist mul
* top
* *det
* genvar $ratfac
17 varlist header $scalarmatrixp $sparse
18 $algebraic
*rank
* *mat
*))
23 (defmvar $matrix_element_mult
"*") ;;; Else, most useful when "."
24 (defmvar $matrix_element_add
"+")
25 (defmvar $matrix_element_transpose nil
)
29 ;;I believe that all the code now stores arrays in the value cell
30 (defun get-array-pointer (symbol)
31 "There may be nesting of functions and we may well need to apply
33 (if (arrayp symbol
) symbol
(symbol-value symbol
)))
36 (mapcar #'(lambda (y) (cons '(mlist) y
)) x
)) ; Matrix to MACSYMA conversion
39 (mapcar #'cdr x
)) ; MACSYMA to Matrix conversion
41 ;; Transpose a list of lists ll. Example: ((1 2) (3 4)) --> ((1 3) (2 4)).
46 (push (mapcar #'car ll
) acc
)
47 (setq ll
(mapcar #'cdr ll
)))
51 (if (or (null x
) (> nn
(length (car x
))))
56 (if (or (null x
) (= nn
0))
58 (cons (ith (car x
) nn
) (nthcol1 (cdr x
) nn
))))
60 ;; MAYBE THIS FUNCTION SHOULD HAVE AN ARGUMENT TO INDICATE WHO CALLED IT (TO SMASH INTO ERROR MESSAGES)
62 (cond ((atom x
) (merror (intl:gettext
"not a matrix: ~M") x
))
63 ((eq (caar x
) '$matrix
) x
)
64 ((eq (caar x
) 'mlist
) (list '($matrix
) x
))
65 (t (merror (intl:gettext
"not a matrix: ~M") x
))))
69 ((eq (caar x
) '$matrix
) x
)
70 ((eq (caar x
) 'mlist
) (list '($matrix
) x
))))
73 (and (not (atom x
)) (eq (caar x
) '$matrix
)))
75 (defmfun $charpoly
(mat var
)
76 (setq mat
(check mat
))
77 (unless (= (length mat
) (length (cadr mat
)))
78 (merror (intl:gettext
"charpoly: matrix must be square; found ~M rows, ~M columns.") (length mat
) (length (cadr mat
))))
81 (setq mat
(mcx (cdr mat
)))
82 (diagmatrix (length mat
) (list '(mtimes) -
1 var
) '$charpoly
))))
83 (t (newvar var
) (newvarmat1 mat
)
84 (setq mat
(mcx (cdr mat
)))
85 (determinant1 (addmatrix mat
(diagmatrix (length mat
)
86 (list '(mtimes) -
1 var
)
89 (defun disreplist1 (a)
90 (setq header
(list 'mrat
'simp varlist genvar
))
91 (mapcar #'disreplist a
))
94 (mapcar #'(lambda (e) (cons header e
)) a
))
100 (mapcar #'(lambda (e) (cdr (ratrep* e
))) a
))
102 (defun timex (mat1 mat2
)
103 (cond ((equal mat1
1) mat2
)
104 ((and ($matrixp mat1
) ($matrixp mat2
) (null (cdr mat1
)))
105 (ncons '($matrix simp
)))
106 (t (newvarmat mat1 mat2
)
107 (let (($scalarmatrixp
108 (if (and ($listp mat1
) ($listp mat2
)) t $scalarmatrixp
)))
109 (simplifya (timex0 mat1 mat2
) nil
)))))
114 (setq varlist
(nconc (sortgreat vlist
) varlist
))))
117 (cond ((atom a
) (newvar1 a
))
118 ((mbagp a
) (mapc #'lnewvar1
(cdr a
)))
121 (defun newvarmat (mat1 mat2
)
124 (lnewvar1 mat1
) (lnewvar1 mat2
)
125 (setq varlist
(nconc (sortgreat vlist
) varlist
)))))
127 (defun newvarmat1 (a)
128 (cond ($ratmx
(lnewvar a
))))
130 (defun addmatrix (x y
)
131 (setq x
(replist1 x
) y
(replist1 y
))
132 (disreplist1 (addmatrix1 x y
)))
134 (defun addmatrix1 (b c
)
135 (unless (and (= (length b
) (length c
))
136 (= (length (car b
)) (length (car c
))))
137 (merror (intl:gettext
"ADDMATRIX1: attempt to add nonconformable matrices.")))
138 (mapcar #'addrows b c
))
142 (mapcar #'(lambda (i j
) (simplus (list '(mplus) i j
) 1 nil
)) a b
)
143 (mapcar #'ratplus a b
)))
145 (defmfun $determinant
(mat)
146 (cond ((not (or (mbagp mat
) ($matrixp mat
)))
147 (if ($scalarp mat
) mat
(list '(%determinant
) mat
)))
148 (t (setq mat
(check mat
))
149 (unless (= (length mat
) (length (cadr mat
)))
152 "determinant: matrix must be square; found ~M rows, ~M columns.")
154 (length (cdadr mat
))))
155 (cond ((not $ratmx
) (det1 (mcx (cdr mat
))))
156 (t (newvarmat1 mat
) (determinant1 (mcx (cdr mat
))))))))
162 (mtoa '*mat
* (setq *det
* (length m
)) *det
* m
)
163 (setq *det
* (tfgeli0 '*mat
* *det
* *det
*))
164 (ratreduce *det
* mul
*))))
166 (defun determinant1 (x)
167 (catch 'dz
(rdis (det (replist1 x
)))))
170 (prog (row mdl lindex tuplel n id md lt
)
171 (setq mat
(reverse mat
))
172 (setq n
(length mat
) md
(car mat
))
173 (setq mat
(cdr mat
)) (setq lindex
(nreverse (index* n
)) tuplel
(mapcar #'list lindex
))
174 loop1
(when (null mat
) (return (car md
)))
176 (mapcar #'(lambda(a b
) (setq mdl
(nconc mdl
(list a b
)))) tuplel md
)
180 (setq lt
(setq tuplel
(nextlevel tuplel lindex
)))
181 loop2
(when (null lt
)
182 (setq md
(nreverse md
))
184 (setq id
(car lt
) lt
(cdr lt
))
185 (setq md
(cons (compumd id row
) md
))
190 loop
(cond ((null l
) (return nil
))
191 ((equal e
(car l
)) (return (cadr l
))))
195 (defun compumd (id row
)
196 (prog (e minor i d sign ans
)
197 (setq ans
0 sign -
1 i id
)
198 loop
(when (null i
) (return ans
))
199 (setq d
(car i
) i
(cdr i
) sign
(* -
1 sign
))
200 (cond ((equal (setq e
(ith row d
)) 0)
202 ((equal (setq minor
(assoo (delete d
(copy-tree id
) :test
#'equal
) mdl
)) 0)
205 (if (and (equal $matrix_element_mult
"*")
206 (equal $matrix_element_add
"+"))
207 (add ans
(mul sign e minor
)) ;fast common case
208 (mapply $matrix_element_add
210 (mapply $matrix_element_mult
212 $matrix_element_mult
))
213 $matrix_element_add
)))
217 (mapcar #'(lambda (j) (append l1
(list j
))) l2
))
219 (defun nextlevel (tuplel lindex
)
221 loop
(when (null tuplel
) (return ans
))
224 li
(cdr (nthcdr (1- (car (last l
))) lindex
)))
225 (when (null li
) (go loop
))
226 (setq ans
(nconc ans
(apdl l li
)))
230 (cond ($sparse
(mtoa '*mat
* (length x
) (length x
)
231 (mapcar #'(lambda (x) (mapcar #'(lambda (y) (ncons y
)) x
))x
))
232 (sprdet '*mat
* (length x
)))
236 (cons '($matrix
) (mxc (diagmatrix n
1 '$ident
))))
238 (defmfun $diagmatrix
(n var
)
239 (cons '($matrix
) (mxc (diagmatrix n var
'$diagmatrix
))))
241 (defun diagmatrix (n var fn
)
243 (when (or (not (fixnump n
)) (minusp n
))
244 (improper-arg-err n fn
))
246 loop
(if (zerop i
) (return ans
))
247 (setq ans
(cons (onen i n var
0) ans
) i
(1- i
))
250 ;; ATOMAT GENERATES A MATRIX FROM A MXN ARRAY BY TAKING COLUMNS S TO N
252 (defun atomat (name m n s
)
253 (setq name
(get-array-pointer name
))
257 loop1
(when (= m
1) (return mat
))
266 (meval (list (list name
'array
) m j
))
268 (push (or d
'(0 .
1)) row
)
271 (defmfun $invert_by_gausselim
(k)
272 (let ((*inv
* t
) *det
* top
* mul
* ($ratmx t
) (ratmx $ratmx
) $ratfac $sparse
)
273 (cond ((atom k
) ($nounify
'$inverx
) (list '(%inverx
) k
))
274 (t (newvarmat1 (setq k
(check k
)))
275 (setq k
(invert1 (replist1 (mcx (cdr k
)))))
276 (setq k
(cond ($detout
`((mtimes)
277 ((mexpt) ,(rdis (or *det
* '(1 .
1))) -
1)
278 (($matrix
) ,@(mxc (disreplist1 k
)))))
279 (t (cons '($matrix
) (mxc (disreplist1 k
))))))
280 (cond ((and ratmx
(not $detout
))
281 (fmapl1 #'(lambda (x) x
) k
))
282 ((not ratmx
) ($totaldisrep k
))
285 (defun diaginv (ax m
)
286 (setq ax
(get-array-pointer ax
))
287 (cond ($detout
(setq *det
* 1)
290 (setq *det
* (plcm *det
* (car (aref ax i i
)))))
291 (setq *det
* (cons *det
* 1))))
295 (setq elm
(aref ax i i
))
296 (setf (aref ax i
(+ m i
))
297 (cond ($detout
(cons (ptimes (cdr elm
)
298 (pquotient (car *det
*) (car elm
))) 1))
299 (t (ratinvert elm
))))))
303 (setq l
(length k
) i
1)
304 (cond ((= l
(length (car k
))) nil
)
305 (t(merror (intl:gettext
"invert: matrix must be square; found ~M rows, ~M columns.") l
(length (car k
)))))
306 loop
(cond ((null k
) (go l1
)))
308 (setq g
(nconc g
(list (nconc r
(onen i l
'(1 .
1) '(0 .
1))))))
309 (setq k
(cdr k
) i
(1+ i
))
312 (mtoa '*mat
* (setq m
(length k
)) (setq n
(length (car k
))) k
)
314 (cond ((diagp '*mat
* m
) (diaginv '*mat
* m
)) (t (tfgeli0 '*mat
* m n
)))
315 (setq k
(atomat '*mat
* m n
(1+ m
)))
321 (declare (fixnum i j
))
322 (setq ax
(get-array-pointer ax
))
323 loop1
(setq i
(1+ i
) j
0)
324 (cond ((> i m
) (return t
)))
326 (cond ((> j m
) (go loop1
))
327 ((and (not (= i j
)) (equal (aref ax i j
) '(0 .
1))) nil
)
328 ((and (= i j
) (not (equal (aref ax i j
) '(0 .
1)))) nil
)
332 (defun tfgeli0 (x m n
)
333 (cond ((or $sparse
*det
*) (tfgeli x m n
))
334 (t (tfgeli x m n
) (diaglize1 x m n
))))
336 ;; TWO-STEP FRACTION-FREE GAUSSIAN ELIMINATION ROUTINE
338 (defun ritediv (x m n a
)
339 (declare (fixnum m n
))
340 (setq x
(get-array-pointer x
))
341 (prog ((j 0) (i 0) d
)
342 (declare (fixnum i j
))
344 loop1
(when (zerop i
) (return nil
))
345 (setf (aref x i i
) nil
)
347 loop
(cond ((= j n
) (decf i
) (go loop1
)))
350 (setf (aref x i j
) (cons (aref x i j
) 1))
352 (setq d
(ignore-rat-err (pquotient (aref x i j
) a
)))
353 (setq d
(cond (d (cons d
1))
354 (t (ratreduce (aref x i j
) a
))))
355 (setf (aref x i j
) d
)
358 (defun diaglize1 (x m n
)
359 (setq x
(get-array-pointer x
))
361 (cond (*det
* (return (ptimes *det
* (aref x m m
)))))
362 (setq *det
* (cons (aref x m m
) 1))
363 (cond ((not $detout
) (return (ritediv x m n
(aref x m m
))))
364 (t (return (ritediv x m n
1))))))
366 ;; Takes an M by N matrix and creates an array containing the elements
367 ;; of the matrix. The array is associated "functionally" with the
369 ;; For CL we have put it in the value cell-WFS. Things still work.
371 (defun mtoa (name m n mat
)
372 (declare (fixnum m n
))
373 (proclaim (list 'special name
))
374 (setf (symbol-value name
) (make-array (list (1+ m
) (1+ n
))))
375 (setq name
(get-array-pointer name
))
381 (row (car mat
) (cdr row
)))
384 (setf (aref name i j
) (car row
)))))
387 (defmfun $echelon
(x)
389 (newvarmat1 (setq x
(check x
))))
390 (let ((*ech
* t
) ($algebraic $algebraic
))
391 (and (not $algebraic
) (some #'algp varlist
) (setq $algebraic t
))
392 (setq x
(cons '($matrix
) (mxc (disreplist1 (echelon1 (replist1 (mcx (cdr x
)))))))))
393 (if $ratmx x
($totaldisrep x
)))
397 (n (length (car x
))))
399 (setq x
(catch 'rank
(tfgeli '*mat
* m n
)))
400 (cond ((and *rank
* x
)
402 (t (echelon2 '*mat
* m n
)))))
404 (defun echelon2 (name m n
)
405 (declare (fixnum m n
))
406 (setq name
(symbol-value name
))
407 (prog ((j 0) row mat a
)
410 loop1
(when (= m
1) (return mat
))
411 (setq m
(1- m
) j
0 a nil
)
413 (setq mat
(cons row mat
) row nil
)
416 (setq row
(nconc row
(ncons (cond ((or (> m j
) (equal (aref name m j
) 0))
418 (a (ratreduce (aref name m j
)a
))
419 (t (setq a
(aref name m j
)) '(1 .
1))))))
428 (triang2 '*mat
* m n
)))
430 (defun triang2 (nam m n
)
431 (declare (fixnum m n
))
432 (setq nam
(get-array-pointer nam
))
433 (prog ((j 0) row mat
)
435 (setf (aref nam
0 0) 1)
437 loop1
(when (= m
1) (return mat
))
441 (setq mat
(cons row mat
) row nil
)
444 (setq row
(nconc row
(ncons (if (> m j
) '(0 .
1) (cons (aref nam m j
) 1)))))
447 (defun onen (n i var fill
)
449 loop
(cond ((= i n
) (setq g
(cons var g
)))
450 ((zerop i
) (return g
))
451 (t (setq g
(cons fill g
))))
458 (cond ((and (null u
) (null v
)) (list '(mtimes) x y
))
459 ((null u
) (timex1 x
(cons '($matrix
) (mcx (cdr v
)))))
460 ((null v
) (timex1 y
(cons '($matrix
) (mcx (cdr u
)))))
461 (t (cons '($matrix mult
) (mxc (multiplymatrices (mcx (cdr u
)) (mcx (cdr v
)))))))))
465 (cond ((not $ratmx
) (setq y
(cdr y
)))
466 (t (setq x
(cdr (ratf x
)) y
(replist1 (cdr y
)))))
472 (return (cons '($matrix mult
)
473 (mxc (cond ((not $ratmx
) c
) (t (disreplist1 c
))))))))
474 (setq c
(nconc c
(list (timesrow x
(car y
)))) y
(cdr y
))
477 (defun multiplymatrices (x y
)
478 (cond ((and (null (cdr y
)) (null (cdr x
)))
479 (and (cdar x
) (setq y
(transpose y
))))
480 ((and (null (cdar x
)) (null (cdar y
)))
481 (and (cdr y
) (setq x
(transpose x
)))))
482 (cond ((not (= (length (car x
)) (length y
)))
483 (cond ((and (null (cdr y
)) (= (length (car x
)) (length (car y
))))
484 (setq y
(transpose y
)))
485 (t (merror (intl:gettext
"MULTIPLYMATRICES: attempt to multiply nonconformable matrices."))))))
486 (cond ((not $ratmx
) (multmat x y
))
487 (t (setq x
(replist1 x
) y
(replist1 y
))
488 (disreplist1 (multmat x y
)))))
491 (prog (mat row yt rowx
)
492 (setq yt
(transpose y
))
493 loop1
(when (null x
) (return mat
))
494 (setq rowx
(car x
) y yt
)
496 (setq mat
(nconc mat
(ncons row
)) x
(cdr x
) row nil
)
498 (setq row
(nconc row
(ncons (multl rowx
(car y
)))) y
(cdr y
))
501 ;;; This actually takes the inner product of the two vectors.
502 ;;; I check for the most common cases for speed. "*" is a slight
503 ;;; violation of data abstraction here. The parser should turn "*" into
504 ;;; MTIMES, well, it may someday, which will break this code. Don't
505 ;;; hold your breath.
508 (cond ((equal $matrix_element_add
"+")
509 (do ((ans (if (not $ratmx
) 0 '(0 .
1))
511 (cond ((equal $matrix_element_mult
"*")
512 (add ans
(mul (car a
) (car b
))))
513 ((equal $matrix_element_mult
".")
514 (add ans
(ncmul (car a
) (car b
))))
517 (meval `((,(getopr $matrix_element_mult
))
518 ((mquote simp
) ,(car a
))
519 ((mquote simp
) ,(car b
))))))))
521 (ratplus ans
(rattimes (car a
) (car b
) t
)))))
526 (mapply (getopr $matrix_element_add
)
527 (mapcar #'(lambda (u v
)
528 (meval `((,(getopr $matrix_element_mult
))
530 ((mquote simp
) ,v
))))
532 (getopr $matrix_element_add
)))))
535 (nreverse (sort (copy-list l
) fn
)))
537 (defun powerx (mat x
)
539 (cond ((not (fixnump x
))
540 (return (list '(mncexpt simp
) mat x
)))
541 ((= x
1) (return mat
))
543 (setq x
(- x
) mat
($invert mat
))
545 (return (let ((*inv
* '$detout
))
546 (mul2* (power* (cadr mat
) x
)
547 (fmapl1 #'(lambda (x) x
)
548 (powerx (caddr mat
) x
)))))))))
549 (newvarmat1 (setq mat
(check mat
)))
550 (setq n
1 mat
(mcx (cdr mat
)) y mat
)
552 (let (($scalarmatrixp
(if (eq $scalarmatrixp
'$all
) '$all
)))
553 (return (simplify (cons '($matrix mult
) (mxc y
))))))
554 (setq y
(multiplymatrices y mat
) n
(1+ n
))
557 ;; The following $ALGEBRAIC code is so that
558 ;; RANK(MATRIX([1-SQRT(5),2],[-2,1+SQRT(5)])); will give 1.
562 (let ((*rank
* t
) ($ratmx t
) ($algebraic $algebraic
))
563 (newvarmat1 (setq x
(check x
)))
564 (and (not $algebraic
) (some #'algp varlist
) (setq $algebraic t
))
565 (setq x
(replist1 (mcx (cdr x
))))
566 (mtoa '*mat
* (length x
) (length (car x
)) x
)
567 (tfgeli '*mat
* (length x
) (length (car x
)))))
569 (defun replacerow (i y x
)
572 (cons (car x
) (replacerow (1- i
) y
(cdr x
)))))
574 (defun timesrow (y row
)
576 (when (and $ratmx
(atom y
) y
)
577 (setq y
(cdr (ratf y
))))
578 loop
(when (null row
) (return ans
))
579 (setq ans
(nconc ans
(list (if (not $ratmx
)
580 (simptimes (list '(mtimes) y
(car row
)) 1 nil
)
581 (rattimes y
(car row
) t
)))))
585 (defmfun $triangularize
(x)
587 (newvarmat1 (setq x
(check x
))))
588 (let (($algebraic $algebraic
))
589 (and (not $algebraic
) (some #'algp varlist
) (setq $algebraic t
))
590 (setq x
(cons '($matrix
) (mxc (disreplist1 (triang (replist1 (mcx (cdr x
)))))))))
591 (if $ratmx x
($totaldisrep x
)))
593 (defmfun $col
(mat n
)
594 (cons '($matrix
) (mxc (transpose (list (nthcol (mcx (cdr (check mat
))) n
))))))
596 (defun deletecol (n x
)
599 loop
(when (null m
) (return g
))
600 (setq g
(nconc g
(ncons (deleterow n
(car m
)))) m
(cdr m
))
603 (defun deleterow (i m
)
604 (cond ((or (null m
) (< i
0)) (merror (intl:gettext
"DELETEROW: matrix is null, or index is negative.")))
606 (t (cons (car m
) (deleterow (1- i
) (cdr m
))))))
608 (defmfun $minor
(mat m n
)
609 (cons '($matrix
) (mxc (minor m n
(mcx (cdr (check mat
)))))))
612 (deletecol j
(deleterow i m
)))
614 (defmfun $row
(mat m
)
615 (cons '($matrix
) (mxc (list (ith (mcx (cdr (check mat
))) m
)))))
617 (defmfun $setelmx
(elm m n mat
)
619 ((not (and (integerp m
) (integerp n
)))
620 (merror (intl:gettext
"setelmx: indices must be integers; found: ~M, ~M") m n
))
621 ((not ($matrixp mat
))
622 (merror (intl:gettext
"setelmx: last argument must be a matrix; found: ~M") mat
))
623 ((not (and (> m
0) (> n
0) (> (length mat
) m
) (> (length (cadr mat
)) n
)))
624 (merror (intl:gettext
"setelmx: no such element [~M, ~M]") m n
)))
625 (rplaca (nthcdr n
(car (nthcdr m mat
))) elm
) mat
)
627 ;;; Here the function transpose can actually do simplification of
628 ;;; its argument. TRANSPOSE(TRANSPOSE(FOO)) => FOO.
629 ;;; If you think this is a hack, well, realize that the hack is
630 ;;; actually the fact that TRANSPOSE can return a noun form.
634 (defmfun $transpose
(mat)
635 (cond ((not (mxorlistp mat
))
636 (cond ((and (not (atom mat
)) (member (mop mat
) '($transpose %transpose
) :test
#'eq
))
640 `((mplus) .
,(mapcar #'$transpose
(cdr mat
))))
642 `((mtimes) .
,(mapcar #'$transpose
(cdr mat
))))
644 `((mnctimes) .
,(nreverse (mapcar #'$transpose
(cdr mat
)))))
646 (destructuring-let (((mat pow
) (cdr mat
)))
647 `((mncexpt) ,($transpose mat
) ,pow
)))
648 (t ($nounify
'$transpose
) (list '(%transpose
) mat
))))
650 (let ((ans (transpose (mcx (cdr (check mat
))))))
651 (cond ($matrix_element_transpose
652 (setq ans
(mapcar #'(lambda (u) (mapcar #'transpose-els u
))
654 `(($matrix
) .
,(mxc ans
))))))
656 ;;; THIS IS FOR TRANSPOSING THE ELEMENTS OF A MATRIX
657 ;;; A hack for Block matricies and tensors.
659 (defun transpose-els (elem)
660 (cond ((eq $matrix_element_transpose
'$transpose
)
662 ((eq $matrix_element_transpose
'$nonscalars
)
663 (if ($nonscalarp elem
)
667 (meval `((,(getopr $matrix_element_transpose
)) ((mquote simp
) ,elem
))))))
670 (defmfun $submatrix
(&rest x
)
672 l1
(when (numberp (car x
))
676 (setq c
(nreverse (bbsort (cdr x
) #'>))
677 r
(nreverse (bbsort r
#'>)))
678 (setq x
(mcx (cdar x
)))
681 (setq x
(deleterow (car r
) x
)))
684 b
(when (null c
) (return (cons '($matrix
) (mxc x
))))
685 (setq x
(deletecol (car c
) x
) c
(cdr c
))
689 (defmfun $list_matrix_entries
(m)
691 (merror (intl:gettext
"list_matrix_entries: argument must be a matrix; found: ~M") m
))
692 (cons (if (null (cdr m
)) '(mlist) (caadr m
))
693 (loop for row in
(cdr m
) append
(cdr row
))))