matrices.scm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Matrices
  21. (declare (usual-integrations))
  22. (define (m:type m) matrix-type-tag)
  23. (define (m:type-predicate m) matrix-quantity?)
  24. ;;; The matrix type is a structural type, providing a means of
  25. ;;; combining other objects. In this system an explicit matrix is a
  26. ;;; tagged array. An array is represented as a scheme vector of rows,
  27. ;;; where each row is a scheme vector of elements.
  28. #|
  29. (*matrix* (nrows . ncols)
  30. #( #( a11 a12 ...)
  31. #( a21 a22 ...)
  32. ...))
  33. |#
  34. (define (tag-matrix nrows ncols array)
  35. (list matrix-type-tag (cons nrows ncols) array))
  36. (define (m:num-rows matrix)
  37. (caadr matrix))
  38. (define (m:num-cols matrix)
  39. (cdadr matrix))
  40. (define (matrix->array matrix)
  41. (caddr matrix))
  42. (define (array->matrix array)
  43. (assert (and (vector? array) (vector-forall vector? array))
  44. "Not an array -- ARRAY->MATRIX" array)
  45. (let ((nrows (num-rows array)) (ncols (num-cols array)))
  46. (assert
  47. (vector-forall (lambda (row) (fix:= (vector-length row) ncols))
  48. array)
  49. "Not all rows have same length -- ARRAY->MATRIX" array)
  50. (tag-matrix nrows ncols array)))
  51. (define (m:dimension mat)
  52. (assert (matrix? mat) "Not a matrix -- DIMENSION" mat)
  53. (let ((d (m:num-rows mat)))
  54. (assert (fix:= d (m:num-cols mat))
  55. "Not a square matrix -- DIMENSION" mat)
  56. d))
  57. (define (matrix-size mat)
  58. (assert (matrix? mat) "Not a matrix -- SIZE" mat)
  59. (fix:* (m:num-rows mat) (m:num-cols mat)))
  60. ;;; Single columns or rows are often important.
  61. (define (column-matrix? m)
  62. (and (matrix? m)
  63. (fix:= (m:num-cols m) 1)))
  64. (define (row-matrix? m)
  65. (and (matrix? m)
  66. (fix:= (m:num-rows m) 1)))
  67. ;;; Sometimes Scheme vectors need to be coerced to matrices
  68. (define (vector->row-matrix v)
  69. (assert (vector? v))
  70. (tag-matrix 1 (vector-length v) (vector v)))
  71. ;;; FBE start: move assertion
  72. (define (vector->column-matrix v)
  73. ;; (assert (vector? v))
  74. (define (vector->column-array v)
  75. (make-initialized-vector (vector-length v)
  76. (lambda (i)
  77. (vector (vector-ref v i)))))
  78. (assert (vector? v))
  79. (tag-matrix (vector-length v) 1 (vector->column-array v)))
  80. (define (row-matrix . args)
  81. (vector->row-matrix (apply vector args)))
  82. (define (column-matrix . args)
  83. (vector->column-matrix (apply vector args)))
  84. ;;; We may need to extract a scheme vector from a matrix
  85. (define (column-matrix->vector m)
  86. (assert (column-matrix? m))
  87. (nth-col (matrix->array m) 0))
  88. (define (row-matrix->vector m)
  89. (assert (row-matrix? m))
  90. (nth-row (matrix->array m) 0))
  91. (define (m:nth-row m n)
  92. (nth-row (matrix->array m) n))
  93. (define (m:nth-col m n)
  94. (nth-col (matrix->array m) n))
  95. (define (m:diagonal m)
  96. (let ((rows (m:dimension m)))
  97. (make-initialized-vector rows
  98. (lambda (i) (matrix-ref m i i)))))
  99. (define (literal-matrix name nrows ncols)
  100. (m:generate nrows ncols
  101. (lambda (i j)
  102. (string->symbol
  103. (string-append (symbol->string name)
  104. "^"
  105. (number->string i)
  106. "_"
  107. (number->string j))))))
  108. #|
  109. (literal-matrix 'A 2 3)
  110. #|
  111. (matrix-by-rows (list A^0_0 A^0_1 A^0_2)
  112. (list A^1_0 A^1_1 A^1_2))
  113. |#
  114. |#
  115. (define (literal-column-matrix name nrows)
  116. (m:generate nrows 1
  117. (lambda (i j)
  118. (string->symbol
  119. (string-append (symbol->string name)
  120. "^"
  121. (number->string i))))))
  122. (define (literal-row-matrix name ncols)
  123. (m:generate 1 ncols
  124. (lambda (i j)
  125. (string->symbol
  126. (string-append (symbol->string name)
  127. "_"
  128. (number->string j))))))
  129. ;;; We need to be able to enter matrices easily, in a variety of
  130. ;;; ways.
  131. (define (up->column-matrix v)
  132. (assert (up? v))
  133. (vector->column-matrix (up->vector v)))
  134. (define (column-matrix->up m)
  135. (assert (column-matrix? m))
  136. (vector->up (nth-col (matrix->array m) 0)))
  137. (define (down->row-matrix v)
  138. (assert (down? v))
  139. (vector->row-matrix (down->vector v)))
  140. (define (row-matrix->down m)
  141. (assert (row-matrix? m))
  142. (vector->down (nth-row (matrix->array m) 0)))
  143. (define (matrix-by-rows . rows)
  144. (matrix-by-row-list rows))
  145. (define (matrix-by-row-list rows)
  146. (assert (and (not (null? rows)) (list? (car rows))))
  147. (let ((nrows (length rows)))
  148. (let ((ncols (length (car rows))))
  149. (assert (for-all? (cdr rows)
  150. (lambda (row)
  151. (and (list? row) (fix:= ncols (length row))))))
  152. (m:generate nrows ncols
  153. (lambda (i j)
  154. (list-ref (list-ref rows i) j))))))
  155. (define (matrix-by-cols . cols)
  156. (matrix-by-col-list cols))
  157. (define (matrix-by-col-list cols)
  158. (assert (and (not (null? cols)) (list (car cols))))
  159. (let ((ncols (length cols)))
  160. (let ((nrows (length (car cols))))
  161. (assert (for-all? (cdr cols)
  162. (lambda (col)
  163. (and (list? col) (fix:= nrows (length col))))))
  164. (m:generate nrows ncols
  165. (lambda (i j)
  166. (list-ref (list-ref cols j) i))))))
  167. ;;; Sometimes we need to make a modified matrix
  168. (define (matrix-with-substituted-row A i V)
  169. (tag-matrix (m:num-rows A) (m:num-cols A)
  170. (vector-with-substituted-coord (matrix->array A) i V)))
  171. (define (matrix-ref m i j)
  172. (vector-ref (vector-ref (matrix->array m) i) j))
  173. (define m:ref matrix-ref)
  174. (define (m:generate nrows ncols proc)
  175. (tag-matrix nrows ncols (generate-array nrows ncols proc)))
  176. (define matrix:generate m:generate)
  177. (define (m:transpose m)
  178. (m:generate (m:num-cols m) (m:num-rows m)
  179. (lambda (i j) (matrix-ref m j i))))
  180. (define* ((m:elementwise f) . matrices)
  181. (assert (and (not (null? matrices))
  182. (for-all? matrices matrix?)))
  183. (let ((nrows (m:num-rows (car matrices)))
  184. (ncols (m:num-cols (car matrices))))
  185. (assert (for-all? (cdr matrices)
  186. (lambda (m)
  187. (and (fix:= (m:num-rows m) nrows)
  188. (fix:= (m:num-cols m) ncols)))))
  189. (m:generate nrows ncols
  190. (lambda (i j)
  191. (g:apply f
  192. (map (lambda (m)
  193. (matrix-ref m i j))
  194. matrices))))))
  195. (define matrix:elementwise m:elementwise)
  196. ;;; Submatrices are often used -- here we extract one
  197. (define (m:submatrix A lowrow hirow+1 lowcol hicol+1)
  198. (m:generate (fix:- hirow+1 lowrow) (fix:- hicol+1 lowcol)
  199. (lambda (i j)
  200. (matrix-ref A (fix:+ i lowrow) (fix:+ j lowcol)))))
  201. ;;; A minor is a submatrix obtained from a given matrix
  202. ;;; by dropping a given row and column.
  203. (define (m:minor m i j)
  204. (m:generate (fix:- (m:num-rows m) 1)
  205. (fix:- (m:num-cols m) 1)
  206. (lambda (a b)
  207. (matrix-ref m
  208. (if (fix:< a i)
  209. a
  210. (fix:+ a 1))
  211. (if (fix:< b j)
  212. b
  213. (fix:+ b 1))))))
  214. (define (m:zero? matrix)
  215. (assert (matrix? matrix) "Not a matrix -- ZERO?" matrix)
  216. (let ((m (m:num-rows matrix))
  217. (n (m:num-cols matrix))
  218. (mat (matrix->array matrix)))
  219. (let rowlp ((i 0))
  220. (if (fix:= i m)
  221. #t
  222. (let collp ((j 0))
  223. (if (fix:= j n)
  224. (rowlp (fix:+ i 1))
  225. (if (g:zero? (array-ref mat i j))
  226. (collp (fix:+ j 1))
  227. #f)))))))
  228. (define* (m:make-zero n #:optional m)
  229. (let ((m (if (default-object? m) n m)))
  230. (m:generate n m (lambda (i j) :zero))))
  231. (define (m:zero-like m)
  232. (let ((z (g:zero-like (matrix-ref m 0 0))))
  233. (m:generate (m:num-rows m) (m:num-cols m)
  234. (lambda (i j) z))))
  235. (define (m:make-identity n)
  236. (m:generate n n
  237. (lambda (i j)
  238. (if (fix:= i j) :one :zero))))
  239. (define (m:identity? matrix)
  240. (assert (matrix? matrix)
  241. "Not a matrix -- IDENTITY?" matrix)
  242. (let ((dim (m:num-rows matrix))
  243. (mat (matrix->array matrix)))
  244. (and (fix:= dim (m:num-cols matrix))
  245. (let rowlp ((i 0))
  246. (if (fix:= i dim)
  247. #t
  248. (let collp ((j 0))
  249. (if (fix:= j dim)
  250. (rowlp (fix:+ i 1))
  251. (if (fix:= i j)
  252. (if (g:one? (array-ref mat i j))
  253. (collp (fix:+ j 1))
  254. #f)
  255. (if (g:zero? (array-ref mat i j))
  256. (collp (fix:+ j 1))
  257. #f)))))))))
  258. (define (m:one-like m)
  259. (m:make-identity (m:dimension m)))
  260. (define (m:identity-like m)
  261. (m:make-identity (m:dimension m)))
  262. (define (m:make-diagonal diag)
  263. ;; From a scheme vector DIAG.
  264. (let ((n (vector-length diag)))
  265. (m:generate n n
  266. (lambda (i j)
  267. (if (fix:= i j)
  268. (vector-ref diag i)
  269. :zero)))))
  270. (define (diagonal? matrix)
  271. (assert (matrix? matrix) "Not a matrix -- DIAGONAL?" matrix)
  272. (let ((dim (m:num-rows matrix))
  273. (mat (matrix->array matrix)))
  274. (and (fix:= dim (m:num-cols matrix))
  275. (let rowlp ((i 0))
  276. (if (fix:= i dim)
  277. #t
  278. (let collp ((j 0))
  279. (if (fix:= j dim)
  280. (rowlp (fix:+ i 1))
  281. (if (fix:= i j)
  282. (collp (fix:+ j 1))
  283. (if (g:zero? (array-ref mat i j))
  284. (collp (fix:+ j 1))
  285. #f)))))))))
  286. (define (matrix=matrix m1 m2)
  287. (assert (and (matrix? m1) (matrix? m2)))
  288. (and (fix:= (m:num-rows m1) (m:num-rows m2))
  289. (fix:= (m:num-cols m1) (m:num-cols m2))
  290. (vector-forall
  291. (lambda (row1 row2)
  292. (vector-forall g:= row1 row2))
  293. (matrix->array m1) (matrix->array m2))))
  294. (define (matrix-binary-componentwise binop matrix1 matrix2)
  295. (assert (and (matrix? matrix1) (matrix? matrix2))
  296. "Not a matrix -- addition" (list binop matrix1 matrix2))
  297. (let ((nrows (m:num-rows matrix1))
  298. (ncols (m:num-cols matrix1))
  299. (m1 (matrix->array matrix1))
  300. (m2 (matrix->array matrix2)))
  301. (assert (and (fix:= nrows (m:num-rows matrix2))
  302. (fix:= ncols (m:num-cols matrix2)))
  303. "Matrices of unequal size -- addition"
  304. (list binop matrix1 matrix2))
  305. (tag-matrix nrows ncols
  306. (make-initialized-vector nrows
  307. (lambda (i)
  308. (let ((m1row (vector-ref m1 i))
  309. (m2row (vector-ref m2 i)))
  310. (make-initialized-vector ncols
  311. (lambda (j)
  312. (binop (vector-ref m1row j)
  313. (vector-ref m2row j))))))))))
  314. (define (matrix+matrix matrix1 matrix2)
  315. (matrix-binary-componentwise g:+ matrix1 matrix2))
  316. (define (matrix-matrix matrix1 matrix2)
  317. (matrix-binary-componentwise g:- matrix1 matrix2))
  318. (define (matrix*matrix matrix1 matrix2)
  319. (assert (and (matrix? matrix1) (matrix? matrix2))
  320. "Not a matrix -- *" (list matrix1 matrix2))
  321. (let ((m1r (m:num-rows matrix1))
  322. (m1c (m:num-cols matrix1))
  323. (m2r (m:num-rows matrix2))
  324. (m2c (m:num-cols matrix2))
  325. (m1 (matrix->array matrix1))
  326. (m2 (matrix->array matrix2)))
  327. (assert (fix:= m1c m2r)
  328. "Matrix sizes do not match -- MATRIX*MATRIX"
  329. (list m1 m2))
  330. (let ((m1cm1 (fix:- m1c 1)))
  331. (m:generate m1r m2c
  332. (lambda (i j)
  333. (let ((r1i (vector-ref m1 i)))
  334. (g:sigma (lambda (k)
  335. (g:* (vector-ref r1i k)
  336. (array-ref m2 k j)))
  337. 0
  338. m1cm1)))))))
  339. (define (m:square a)
  340. (matrix*matrix a a))
  341. (define (m:expt M n)
  342. (assert (matrix? M) "Not a matrix -- EXPT")
  343. (cond ((or (not (integer? n)) (inexact? n))
  344. (error "Only integer powers allowed -- M:EXPT"))
  345. ((fix:< n 0)
  346. (m:expt (m:invert M) (fix:- 0 n)))
  347. ((fix:zero? n)
  348. (m:make-identity (m:num-rows M)))
  349. (else
  350. (let loop ((count n))
  351. (cond ((fix:= count 1) M)
  352. ((even? count)
  353. (let ((a (loop (fix:quotient count 2))))
  354. (matrix*matrix a a)))
  355. (else
  356. (matrix*matrix M
  357. (loop (fix:- count 1)))))))))
  358. (define (matrix*scalar matrix k)
  359. (assert (and (matrix? matrix) (scalar? k))
  360. "Not matrix*scalar" (list matrix k))
  361. (let ((m (matrix->array matrix)))
  362. (m:generate (m:num-rows matrix) (m:num-cols matrix)
  363. (lambda (i j) (g:* (array-ref m i j) k)))))
  364. (define (scalar*matrix k matrix)
  365. (assert (and (matrix? matrix) (scalar? k))
  366. "Not matrix*scalar" (list matrix k))
  367. (let ((m (matrix->array matrix)))
  368. (m:generate (m:num-rows matrix) (m:num-cols matrix)
  369. (lambda (i j) (g:* k (array-ref m i j))))))
  370. (define (m:scale k)
  371. (lambda (m) (scalar*matrix k m)))
  372. (define (m:outer-product v1 v2)
  373. (assert (and (column-matrix? v1) (row-matrix? v2)))
  374. (matrix*matrix v1 v2))
  375. (define (m:inner-product v1 v2)
  376. (assert (and (row-matrix? v1) (column-matrix? v2)))
  377. (matrix-ref (matrix*matrix v1 v2) 0 0))
  378. (define (matrix/matrix m1 m2)
  379. (matrix*matrix m1 (m:invert m2)))
  380. ;;; Cleaning up some useful hacks
  381. (define (matrix*up m v)
  382. (column-matrix->up
  383. (matrix*matrix m
  384. (up->column-matrix v))))
  385. (define (down*matrix v m)
  386. (row-matrix->down
  387. (matrix*matrix (down->row-matrix v)
  388. m)))
  389. #| ;;; Unnecessary, since up tuples are vectors
  390. (define (matrix*vector m v)
  391. (column-matrix->vector
  392. (matrix*matrix m
  393. (vector->column-matrix v))))
  394. |#
  395. (define (matrix*vector m v) (matrix*up m v))
  396. ;;; Dangerous, should not be generic.
  397. (define (vector*matrix v m)
  398. (row-matrix->vector
  399. (matrix*matrix (vector->row-matrix v)
  400. m)))
  401. (define (matrix/scalar m k)
  402. (matrix*scalar m (g:invert k)))
  403. (define (scalar/matrix k m)
  404. (scalar*matrix k (m:invert m)))
  405. (define (matrix=scalar m c)
  406. (matrix=matrix m
  407. (scalar*matrix c
  408. (m:make-identity (m:num-rows m)))))
  409. (define (scalar=matrix c m)
  410. (matrix=matrix (scalar*matrix c
  411. (m:make-identity (m:num-rows m)))
  412. m))
  413. (define (matrix+scalar m c)
  414. (matrix+matrix m
  415. (scalar*matrix c
  416. (m:make-identity (m:num-rows m)))))
  417. (define (scalar+matrix c m)
  418. (matrix+matrix (scalar*matrix c
  419. (m:make-identity (m:num-rows m)))
  420. m))
  421. (define (matrix-scalar m c)
  422. (matrix-matrix m
  423. (scalar*matrix c
  424. (m:make-identity (m:num-rows m)))))
  425. (define (scalar-matrix c m)
  426. (matrix-matrix (scalar*matrix c
  427. (m:make-identity (m:num-rows m)))
  428. m))
  429. (define (m:trace matrix)
  430. (assert (matrix? matrix) "Not a matrix -- TRACE")
  431. (let ((rows (m:num-rows matrix))
  432. (m (matrix->array matrix)))
  433. (assert (fix:= rows (m:num-cols matrix))
  434. "Not a square matrix -- TRACE" matrix)
  435. (g:sigma (lambda (j) (array-ref m j j))
  436. 0
  437. (fix:- rows 1))))
  438. (define (m:conjugate mat)
  439. ((m:elementwise g:conjugate) mat))
  440. (define (m:negate mat)
  441. ((m:elementwise g:negate) mat))
  442. (define (m:dot-product-row r1 r2)
  443. (v:dot-product (row-matrix->vector r1)
  444. (row-matrix->vector r2)))
  445. (define (m:dot-product-column c1 c2)
  446. (v:dot-product (column-matrix->vector c1)
  447. (column-matrix->vector c2)))
  448. (define (m:cross-product-row r1 r2)
  449. (vector->row-matrix
  450. (v:cross-product (row-matrix->vector r1)
  451. (row-matrix->vector r2))))
  452. (define (m:cross-product-column c1 c2)
  453. (vector->column-matrix
  454. (v:cross-product (column-matrix->vector c1)
  455. (column-matrix->vector c2))))
  456. (define (m:exp mat)
  457. (series:value exp-series (list mat)))
  458. (define (m:sin mat)
  459. (series:value sin-series (list mat)))
  460. (define (m:cos mat)
  461. (series:value cos-series (list mat)))
  462. ;;; Kleanthes Konaris determinant routine, slightly edited by GJS
  463. ;;; -------------------------------------------------------------
  464. ;;; (iota 4) --> (0 1 2 3), as in APL.
  465. (define (general-determinant add sub mul easy-zero?)
  466. (let ((zero (add)))
  467. (define (det m)
  468. (let ((cache '()))
  469. (define (c-det row active-column-list)
  470. (if (null? (cdr active-column-list)) ;one active column
  471. (matrix-ref m row (car active-column-list))
  472. (let ((value
  473. (assoc (list row active-column-list) cache)))
  474. (if value
  475. (cadr value) ; cache hit!
  476. (let loop ; cache miss!
  477. ((index 0)
  478. (remaining-columns active-column-list)
  479. (answer zero))
  480. (if (null? remaining-columns)
  481. (begin (set! cache
  482. (cons (list (list row
  483. active-column-list)
  484. answer)
  485. cache))
  486. answer)
  487. (let ((term
  488. (matrix-ref m row (car remaining-columns))))
  489. (if (easy-zero? term)
  490. (loop (fix:+ index 1)
  491. (cdr remaining-columns)
  492. answer)
  493. (let ((contrib
  494. (mul term
  495. (c-det (fix:+ row 1)
  496. (delete-nth index
  497. active-column-list)))))
  498. (if (even? index)
  499. (loop (fix:+ index 1)
  500. (cdr remaining-columns)
  501. (add answer contrib))
  502. (loop (fix:+ index 1)
  503. (cdr remaining-columns)
  504. (sub answer contrib))))))))))))
  505. (c-det 0 (iota (m:dimension m)))))
  506. det))
  507. ;;;; Linear equations solved by Cramer's rule.
  508. ;;; Solves an inhomogeneous system of linear equations, A*X=B,
  509. ;;; where the matrix A and the column matrix B are given.
  510. ;;; It returns the column matrix X.
  511. ;;; Unlike LU decomposition, Cramer's rule generalizes to symbolic solutions.
  512. (define (Cramers-rule add sub mul div zero?)
  513. (let ((det (general-determinant add sub mul zero?)))
  514. (define solve
  515. (lambda (A B)
  516. (assert (and (matrix? A)
  517. (column-matrix? B)
  518. (fix:= (m:dimension A) (m:num-rows B))))
  519. (let ((bv (m:nth-col B 0))
  520. (d (det A))
  521. (At (m:transpose A)))
  522. (vector->column-matrix
  523. (make-initialized-vector (vector-length bv)
  524. (lambda (i)
  525. (div (det (matrix-with-substituted-row At i bv))
  526. d)))))))
  527. solve))
  528. ;;; The following implements the classical adjoint formula for the
  529. ;;; inverse of a matrix. This may be useful for symbolic applications.
  530. (define (classical-adjoint-formula zero one add sub mul div zero?)
  531. (let ((det (general-determinant add sub mul zero?)))
  532. (define (matinv A)
  533. (let ((dim (m:dimension A)))
  534. (if (fix:= dim 1)
  535. (m:generate 1 1
  536. (lambda (i j) (div one (matrix-ref A 0 0))))
  537. (let* ((d (det A)) (-d (sub zero d)))
  538. (m:generate dim dim
  539. (lambda (j i)
  540. (if (even? (+ i j))
  541. (div (det (m:minor A i j)) d)
  542. (div (det (m:minor A i j)) -d))))))))
  543. matinv))
  544. (define (easy-zero? x)
  545. (cond ((number? x) (zero? x))
  546. ;; Perhaps some form of easy simplification here?
  547. ;; e.g. substitution of numbers for literals,
  548. ;; and testing for zero result.
  549. (else #f)))
  550. (define matinv-general
  551. (classical-adjoint-formula :zero :one g:+ g:- g:* g:/ easy-zero?))
  552. (define solve-general
  553. (Cramers-rule g:+ g:- g:* g:/ easy-zero?))
  554. (define determinant-general
  555. (general-determinant g:+ g:- g:* easy-zero?))
  556. ;;;LU decomposer, etc, must use correct arithmetic
  557. (define matinv-numerical)
  558. (define solve-numerical)
  559. (define determinant-numerical)
  560. ;;; FBE: make a parameter
  561. (define numerical? (make-parameter #f))
  562. (define (m:invert A)
  563. (if (numerical?) (matinv-numerical A) (matinv-general A)))
  564. (define (m:solve A b)
  565. (if (numerical?) (solve-numerical A b) (solve-general A b)))
  566. (define (m:determinant A)
  567. (if (numerical?) (determinant-numerical A) (determinant-general A)))
  568. (define (m:rsolve b A)
  569. (cond ((up? b)
  570. (column-matrix->up
  571. (m:solve A (up->column-matrix b))))
  572. ((column-matrix? b)
  573. (m:solve A b))
  574. ((down? b)
  575. (row-matrix->down
  576. (m:transpose
  577. (m:solve (m:transpose A)
  578. (m:transpose (down->row-matrix b))))))
  579. ((row-matrix? b)
  580. (m:transpose
  581. (m:solve (m:transpose A)
  582. (m:transpose b))))
  583. (else (error "I don't know how to solve:" b A))))
  584. (define (m:solve-linear A b)
  585. (m:rsolve b A))
  586. (define* (set-numerical! #:optional matinv solve determinant)
  587. (numerical? #t)
  588. (if (not (default-object? matinv)) (set! matinv-numerical matinv))
  589. (if (not (default-object? solve)) (set! solve-numerical solve))
  590. (if (not (default-object? determinant)) (set! determinant-numerical determinant))
  591. 'thank-you)
  592. (define (set-symbolic!)
  593. (numerical? #f)
  594. 'thank-you)
  595. (define (m:apply matrix args)
  596. (m:generate (m:num-rows matrix) (m:num-cols matrix)
  597. (lambda (i j)
  598. (g:apply (matrix-ref matrix i j)
  599. args))))
  600. (define (m:arity mat)
  601. (let ((n (m:num-rows mat)) (m (m:num-cols mat)))
  602. (let rowlp ((i 0) (a *at-least-zero*))
  603. (if (fix:= i n)
  604. a
  605. (let collp ((j 0) (a a))
  606. (if (fix:= j m)
  607. (rowlp (fix:+ i 1) a)
  608. (let ((b
  609. (joint-arity a
  610. (g:arity (matrix-ref mat i j)))))
  611. (if b
  612. (collp (fix:+ j 1) b)
  613. #f))))))))
  614. (define (m:partial-derivative matrix varspecs)
  615. ((m:elementwise
  616. (lambda (f)
  617. (generic:partial-derivative f varspecs)))
  618. matrix))
  619. (define (m:inexact? m)
  620. (vector-exists (lambda (v)
  621. (vector-exists g:inexact? v))
  622. (matrix->array m)))
  623. (define %kernel-matrices-dummy-1
  624. (begin
  625. (assign-operation 'type m:type matrix?)
  626. (assign-operation 'type-predicate m:type-predicate matrix?)
  627. (assign-operation 'arity m:arity matrix?)
  628. (assign-operation 'inexact? m:inexact? matrix?)
  629. (assign-operation 'zero-like m:zero-like matrix?)
  630. (assign-operation 'one-like m:one-like matrix?)
  631. (assign-operation 'identity-like m:identity-like matrix?)
  632. (assign-operation 'zero? m:zero? matrix?)
  633. (assign-operation 'identity? m:identity? matrix?)
  634. (assign-operation 'negate m:negate matrix?)
  635. (assign-operation 'invert m:invert square-matrix?)
  636. (assign-operation 'conjugate m:conjugate matrix?)
  637. (assign-operation 'exp m:exp square-matrix?)
  638. (assign-operation 'sin m:sin square-matrix?)
  639. (assign-operation 'cos m:cos square-matrix?)
  640. (assign-operation '= matrix=matrix matrix? matrix?)
  641. (assign-operation '= matrix=scalar square-matrix? scalar?)
  642. (assign-operation '= scalar=matrix scalar? square-matrix?)
  643. (assign-operation '+ matrix+matrix matrix? matrix?)
  644. (assign-operation '+ matrix+scalar square-matrix? scalar?)
  645. (assign-operation '+ scalar+matrix scalar? square-matrix?)
  646. (assign-operation '- matrix-matrix matrix? matrix?)
  647. (assign-operation '- matrix-scalar square-matrix? scalar?)
  648. (assign-operation '- scalar-matrix scalar? square-matrix?)
  649. (assign-operation '* matrix*matrix matrix? matrix?)
  650. (assign-operation '* matrix*scalar matrix? scalar?)
  651. (assign-operation '* scalar*matrix scalar? matrix?)
  652. (assign-operation '* down*matrix down? matrix?)
  653. (assign-operation '* matrix*up matrix? up?)
  654. (assign-operation '/ matrix/scalar matrix? scalar?)
  655. (assign-operation '/ scalar/matrix scalar? square-matrix?)
  656. (assign-operation '/ m:rsolve column-matrix? square-matrix?)
  657. (assign-operation '/ m:rsolve up? square-matrix?)
  658. (assign-operation '/ m:rsolve down? square-matrix?)
  659. (assign-operation '/ m:rsolve row-matrix? square-matrix?)
  660. (assign-operation '/ matrix/matrix matrix? square-matrix?)
  661. (assign-operation 'dot-product m:dot-product-row row-matrix? row-matrix?)
  662. (assign-operation 'dot-product m:dot-product-column column-matrix? column-matrix?)
  663. (assign-operation 'outer-product m:outer-product column-matrix? row-matrix?)
  664. (assign-operation 'cross-product m:cross-product-row row-matrix? row-matrix?)
  665. (assign-operation 'cross-product m:cross-product-column column-matrix? column-matrix?)
  666. (assign-operation 'expt m:expt square-matrix? exact-integer?)
  667. (assign-operation 'partial-derivative
  668. m:partial-derivative
  669. matrix? any?)
  670. (assign-operation 'apply m:apply matrix? any?)
  671. (assign-operation 'determinant m:determinant square-matrix?)
  672. (assign-operation 'trace m:trace square-matrix?)
  673. (assign-operation 'transpose m:transpose matrix?)
  674. (assign-operation 'dimension m:dimension square-matrix?)
  675. (assign-operation 'dimension m:num-rows column-matrix?)
  676. (assign-operation 'dimension m:num-cols row-matrix?)
  677. (assign-operation 'solve-linear m:solve-linear square-matrix? column-matrix?)
  678. (assign-operation 'solve-linear m:solve-linear square-matrix? up?)
  679. (assign-operation 'solve-linear m:solve-linear square-matrix? row-matrix?)
  680. (assign-operation 'solve-linear m:solve-linear square-matrix? down?)))
  681. ;;; Abstract matrices generalize matrix quantities.
  682. (define (abstract-matrix symbol)
  683. (make-literal abstract-matrix-type-tag symbol))
  684. (define (am:arity v)
  685. ;; Default is matrix of numbers.
  686. (get-property v 'arity *at-least-zero*))
  687. (define (am:zero-like m)
  688. (let ((z (abstract-matrix (list 'zero-like m))))
  689. (add-property! z 'zero #t)
  690. z))
  691. (define (am:one-like m)
  692. (let ((z (abstract-matrix (list 'one-like m))))
  693. (add-property! z 'one #t)
  694. z))
  695. (define (am:id-like m)
  696. (let ((z (abstract-matrix (list 'identity-like m))))
  697. (add-property! z 'one #t)
  698. z))
  699. (define* (make-matrix-combination operator #:optional reverse?)
  700. (if (default-object? reverse?)
  701. (lambda operands
  702. (make-combination abstract-matrix-type-tag
  703. operator operands))
  704. (lambda operands
  705. (make-combination abstract-matrix-type-tag
  706. operator (reverse operands)))))
  707. (define %kernel-matrices-dummy-2
  708. (begin
  709. (assign-operation 'type m:type abstract-matrix?)
  710. (assign-operation 'type-predicate m:type-predicate abstract-matrix?)
  711. (assign-operation 'arity am:arity abstract-matrix?)
  712. (assign-operation 'inexact? (has-property? 'inexact) abstract-matrix?)
  713. (assign-operation 'zero-like am:zero-like abstract-matrix?)
  714. (assign-operation 'zero? (has-property? 'zero) abstract-matrix?)
  715. (assign-operation 'one? (has-property? 'one) abstract-matrix?)
  716. (assign-operation 'identity? (has-property? 'one) abstract-matrix?)
  717. (assign-operation
  718. 'negate (make-matrix-combination 'negate) abstract-matrix?)
  719. (assign-operation
  720. 'invert (make-matrix-combination 'invert) square-abstract-matrix?)
  721. (assign-operation
  722. 'conjugate (make-matrix-combination 'conjugate) abstract-matrix?)
  723. (assign-operation
  724. 'exp (make-matrix-combination 'exp) square-abstract-matrix?)
  725. (assign-operation
  726. 'sin (make-matrix-combination 'sin) square-abstract-matrix?)
  727. (assign-operation
  728. 'cos (make-matrix-combination 'cos) square-abstract-matrix?)
  729. ;(assign-operation
  730. ; '= matrix=matrix abstract-matrix? abstract-matrix?)
  731. (assign-operation
  732. '+ (make-matrix-combination '+) abstract-matrix? abstract-matrix?)
  733. (assign-operation
  734. '+ (make-matrix-combination '+) matrix? abstract-matrix?)
  735. (assign-operation
  736. '+ (make-matrix-combination '+ 'r) abstract-matrix? matrix?)
  737. (assign-operation
  738. '+ (make-matrix-combination '+) scalar? square-abstract-matrix?)
  739. (assign-operation
  740. '+ (make-matrix-combination '+ 'r) square-abstract-matrix? scalar?)
  741. (assign-operation
  742. '- (make-matrix-combination '-) abstract-matrix? abstract-matrix?)
  743. (assign-operation
  744. '- (make-matrix-combination '-) matrix? abstract-matrix?)
  745. (assign-operation
  746. '- (make-matrix-combination '-) abstract-matrix? matrix?)
  747. (assign-operation
  748. '- (make-matrix-combination '-) scalar? square-abstract-matrix?)
  749. (assign-operation
  750. '- (make-matrix-combination '-) square-abstract-matrix? scalar?)
  751. (assign-operation
  752. '* (make-matrix-combination '*) abstract-matrix? abstract-matrix?)
  753. (assign-operation
  754. '* (make-matrix-combination '*) matrix? abstract-matrix?)
  755. (assign-operation
  756. '* (make-matrix-combination '*) abstract-matrix? matrix?)
  757. (assign-operation
  758. '* (make-matrix-combination '*) scalar? abstract-matrix?)
  759. (assign-operation
  760. '* (make-matrix-combination '* 'r) abstract-matrix? scalar?)
  761. (assign-operation
  762. '/ (make-matrix-combination '/) abstract-matrix? square-abstract-matrix?)
  763. (assign-operation
  764. '/ (make-matrix-combination '/) matrix? square-abstract-matrix?)
  765. (assign-operation
  766. '/ (make-matrix-combination '/) abstract-matrix? square-matrix?)
  767. (assign-operation
  768. '/ (make-matrix-combination '/) scalar? square-abstract-matrix?)
  769. (assign-operation
  770. '/ (make-matrix-combination '/) abstract-matrix? scalar?)
  771. (assign-operation
  772. '/ (make-matrix-combination '/) vector-quantity? square-abstract-matrix?)
  773. (assign-operation
  774. 'expt (make-matrix-combination 'expt) square-abstract-matrix? exact-integer?)
  775. (assign-operation
  776. 'partial-derivative
  777. (make-matrix-combination 'partial-derivative)
  778. abstract-matrix? any?)))
  779. ;(assign-operation 'apply m:apply abstract-matrix? any?)