quaternion.scm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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. ;;;; Quaternions
  21. ;;; 13 August 1998 -- rfrankel, gjs
  22. ;;; 12 June 2013 -- gjs
  23. (declare (usual-integrations))
  24. (define (q:type v) quaternion-type-tag)
  25. (define (q:type-predicate v) quaternion-quantity?)
  26. (define (make-quaternion v)
  27. (list quaternion-type-tag v))
  28. (define q:make make-quaternion)
  29. (define (quaternion r i j k)
  30. (make-quaternion (vector r i j k)))
  31. (define (quaternion->vector q)
  32. (cadr q))
  33. (define q:->vector quaternion->vector)
  34. (define (quaternion-ref q i)
  35. (vector-ref (quaternion->vector q) i))
  36. (define q:ref quaternion-ref)
  37. (define (real&3vector->quaternion r v)
  38. (quaternion r
  39. (vector-ref v 0)
  40. (vector-ref v 1)
  41. (vector-ref v 2)))
  42. (define q:real&3vector-> real&3vector->quaternion)
  43. (define (quaternion->3vector q)
  44. (vector-tail (quaternion->vector q) 1))
  45. (define q:3vector quaternion->3vector)
  46. (define (quaternion->real-part q)
  47. (quaternion-ref q 0))
  48. (define q:real-part quaternion->real-part)
  49. (define (quaternion+quaternion q1 q2)
  50. (make-quaternion
  51. (make-initialized-vector 4
  52. (lambda (i)
  53. (g:+ (quaternion-ref q1 i)
  54. (quaternion-ref q2 i))))))
  55. (define q:+ quaternion+quaternion)
  56. (define (quaternion-quaternion q1 q2)
  57. (make-quaternion
  58. (make-initialized-vector 4
  59. (lambda (i)
  60. (g:- (quaternion-ref q1 i)
  61. (quaternion-ref q2 i))))))
  62. (define q:- quaternion-quaternion)
  63. (define (quaternion*quaternion q1 q2)
  64. (let ((r1 (quaternion-ref q1 0))
  65. (i1 (quaternion-ref q1 1))
  66. (j1 (quaternion-ref q1 2))
  67. (k1 (quaternion-ref q1 3))
  68. (r2 (quaternion-ref q2 0))
  69. (i2 (quaternion-ref q2 1))
  70. (j2 (quaternion-ref q2 2))
  71. (k2 (quaternion-ref q2 3)))
  72. (make-quaternion
  73. (vector (g:- (g:* r1 r2) (g:+ (g:* i1 i2) (g:* j1 j2) (g:* k1 k2)))
  74. (g:+ (g:* r1 i2) (g:* i1 r2) (g:* j1 k2) (g:* -1 k1 j2))
  75. (g:+ (g:* r1 j2) (g:* -1 i1 k2) (g:* j1 r2) (g:* k1 i2))
  76. (g:+ (g:* r1 k2) (g:* i1 j2) (g:* -1 j1 i2) (g:* k1 r2))))))
  77. (define q:* quaternion*quaternion)
  78. (define (q:conjugate q)
  79. (quaternion (quaternion-ref q 0)
  80. (g:- (quaternion-ref q 1))
  81. (g:- (quaternion-ref q 2))
  82. (g:- (quaternion-ref q 3))))
  83. (define (q:negate q)
  84. (make-quaternion
  85. (make-initialized-vector 4
  86. (lambda (i)
  87. (g:- (quaternion-ref q i))))))
  88. (define (scalar*quaternion s q)
  89. (make-quaternion
  90. (make-initialized-vector 4
  91. (lambda (i)
  92. (g:* s (quaternion-ref q i))))))
  93. (define (quaternion*scalar q s)
  94. (make-quaternion
  95. (make-initialized-vector 4
  96. (lambda (i)
  97. (g:* (quaternion-ref q i) s)))))
  98. (define (quaternion/scalar q s)
  99. (make-quaternion
  100. (make-initialized-vector 4
  101. (lambda (i)
  102. (g:/ (quaternion-ref q i) s)))))
  103. (define (q:invert q)
  104. (quaternion/scalar (q:conjugate q)
  105. (g:+ (g:square (quaternion-ref q 0))
  106. (g:square (quaternion-ref q 1))
  107. (g:square (quaternion-ref q 2))
  108. (g:square (quaternion-ref q 3)))))
  109. (define (quaternion/quaternion q1 q2)
  110. (quaternion*quaternion q1 (q:invert q2)))
  111. (define q:/ quaternion/quaternion)
  112. (define (q:magnitude q)
  113. (g:sqrt (g:+ (g:square (quaternion-ref q 0))
  114. (g:square (quaternion-ref q 1))
  115. (g:square (quaternion-ref q 2))
  116. (g:square (quaternion-ref q 3)))))
  117. (define (q:make-unit q)
  118. (quaternion/scalar q (q:magnitude q)))
  119. (define (q:unit? q)
  120. (let ((v (q:->vector q)))
  121. (g:one? (v:dot-product v v))))
  122. (define (q:exp q)
  123. (let ((v (quaternion->3vector q))
  124. (a (quaternion->real-part q)))
  125. (let ((vv (euclidean-norm v)))
  126. (g:* (g:exp a)
  127. (real&3vector->quaternion (g:cos vv)
  128. (g:* (g:sin vv)
  129. (g:/ v vv)))))))
  130. (define (q:log q)
  131. (let ((v (quaternion->3vector q))
  132. (a (quaternion->real-part q))
  133. (qq (euclidean-norm (quaternion->vector q))))
  134. (let ((vv (euclidean-norm v)))
  135. (real&3vector->quaternion (g:log qq)
  136. (g:* (g:acos (g:/ a qq))
  137. (g:/ v vv))))))
  138. (define (q:zero-like q)
  139. (make-quaternion
  140. (make-vector 4 0)))
  141. (define (q:zero? q)
  142. (and (g:zero? (quaternion-ref q 0))
  143. (g:zero? (quaternion-ref q 1))
  144. (g:zero? (quaternion-ref q 2))
  145. (g:zero? (quaternion-ref q 3))))
  146. (define (q:= q1 q2)
  147. (and (g:= (quaternion-ref q1 0) (quaternion-ref q2 0))
  148. (g:= (quaternion-ref q1 1) (quaternion-ref q2 1))
  149. (g:= (quaternion-ref q1 2) (quaternion-ref q2 2))
  150. (g:= (quaternion-ref q1 3) (quaternion-ref q2 3))))
  151. (define (q:inexact? q)
  152. (or (g:inexact? (quaternion-ref q 0))
  153. (g:inexact? (quaternion-ref q 1))
  154. (g:inexact? (quaternion-ref q 2))
  155. (g:inexact? (quaternion-ref q 3))))
  156. (define (q:apply q args)
  157. (let ((vec (quaternion->vector q)))
  158. (make-quaternion
  159. (v:generate (vector-length vec)
  160. (lambda (i)
  161. (g:apply (vector-ref vec i) args))))))
  162. (define (q:arity q)
  163. (let ((v (quaternion->vector q)))
  164. (let ((n 4))
  165. (let lp ((i 1) (a (g:arity (vector-ref v 0))))
  166. (if (fix:= i n)
  167. a
  168. (let ((b (joint-arity a (g:arity (vector-ref v i)))))
  169. (if b
  170. (lp (+ i 1) b)
  171. #f)))))))
  172. (define (q:partial-derivative q varspecs)
  173. (let ((v (quaternion->vector q)))
  174. (make-quaternion
  175. ((v:elementwise
  176. (lambda (f)
  177. (generic:partial-derivative f varspecs)))
  178. v))))
  179. ;;; Quaternions as 4x4 matrices
  180. (define q:1
  181. (matrix-by-rows (list 1 0 0 0) (list 0 1 0 0) (list 0 0 1 0) (list 0 0 0 1)))
  182. (define q:i
  183. (matrix-by-rows (list 0 1 0 0) (list -1 0 0 0) (list 0 0 0 -1) (list 0 0 1 0)))
  184. (define q:j
  185. (matrix-by-rows (list 0 0 1 0) (list 0 0 0 1) (list -1 0 0 0) (list 0 -1 0 0)))
  186. (define q:k
  187. (matrix-by-rows (list 0 0 0 1) (list 0 0 -1 0) (list 0 1 0 0) (list -1 0 0 0)))
  188. (define s:1 (Mmn->A^m_n q:1))
  189. (define s:i (Mmn->A^m_n q:i))
  190. (define s:j (Mmn->A^m_n q:j))
  191. (define s:k (Mmn->A^m_n q:k))
  192. (define (quaternion->4x4 q)
  193. (let ((r (quaternion-ref q 0))
  194. (x (quaternion-ref q 1))
  195. (y (quaternion-ref q 2))
  196. (z (quaternion-ref q 3)))
  197. (matrix+matrix (matrix+matrix (scalar*matrix r q:1)
  198. (scalar*matrix x q:i))
  199. (matrix+matrix (scalar*matrix y q:j)
  200. (scalar*matrix z q:k)))))
  201. (define q:->4x4 quaternion->4x4)
  202. (define (4x4->quaternion 4-matrix)
  203. (make-quaternion (m:nth-row 4-matrix 0)))
  204. (define q:4x4-> 4x4->quaternion)
  205. ;;; Quaternions and 3D rotations
  206. ;;; Given a axis (a unit 3-vector) and an angle
  207. (define (angle-axis->quaternion theta axis)
  208. ;; (assert (v:unit? axis))
  209. ;; This assertion is really:
  210. (let ((v (g:simplify (v:dot-product axis axis))))
  211. (assume! `(= ,v 1) 'angle-axis->quaternion))
  212. (real&3vector->quaternion (g:cos (g:/ theta 2))
  213. (g:* (g:sin (g:/ theta 2))
  214. axis)))
  215. (define q:angle-axis-> angle-axis->quaternion)
  216. ;;; Problem: this is singular if the vector part is zero.
  217. (define* (quaternion->angle-axis q #:optional continue)
  218. (assert (quaternion? q))
  219. (let ((continue
  220. (if (default-object? continue) list continue)))
  221. (let* ((v (q:3vector q))
  222. (theta (g:* 2 (g:atan (euclidean-norm v)
  223. (q:real-part q))))
  224. (axis (vector/scalar v (euclidean-norm v))))
  225. (continue theta axis))))
  226. (define q:->angle-axis quaternion->angle-axis)
  227. #|
  228. (quaternion->angle-axis
  229. (angle-axis->quaternion 'theta
  230. (up 'x 'y (sqrt (- 1 (square 'x) (square 'y))))))
  231. #|
  232. (theta (up x y (sqrt (+ 1 (* -1 (expt x 2)) (* -1 (expt y 2))))))
  233. |#
  234. |#
  235. ;;; To rotate a 3-vector by the angle prescribed by a unit quaternion.
  236. (define (q:rotate q)
  237. (assert (quaternion? q))
  238. ;;(assert (q:unit? q))
  239. ;; This assertion is really:
  240. (let* ((vv (quaternion->vector q))
  241. (v (g:simplify (v:dot-product vv vv))))
  242. (assume! `(= ,v 1) 'q:rotate))
  243. (let ((q* (q:conjugate q)))
  244. (define (the-rotation 3-vector)
  245. (quaternion->3vector
  246. (quaternion*quaternion q
  247. (quaternion*quaternion
  248. (real&3vector->quaternion 0 3-vector)
  249. q*))))
  250. the-rotation))
  251. #|
  252. ;;; Relation to rotation matrices
  253. ;;; Trig method. Has problems if real part = 0.
  254. (define (rotation-matrix->quaternion M)
  255. ;;(assert (orthogonal-matrix? M))
  256. (let ((v (column-matrix->vector
  257. (antisymmetric->column-matrix
  258. (g:* 1/2 (g:- M (m:transpose M))))))
  259. (cos-o (g:* 1/2 (g:- (m:trace M) 1))))
  260. (let ((sin-o (euclidean-norm v)))
  261. (let ((o (g:atan sin-o cos-o)))
  262. (let ((qv
  263. (g:* (g:sin (g:/ o 2))
  264. (g:/ v (g:sin o)))))
  265. (real&3vector->quaternion
  266. (g:cos (g:/ o 2)) qv))))))
  267. ;;; From Matt Mason, Lecture 7, Mechanics of Manipulation, Spring 2012.
  268. (define (rotation-matrix->quaternion-mason M)
  269. (let ((r11 (matrix-ref M 0 0)) (r12 (matrix-ref M 0 1)) (r13 (matrix-ref M 0 2))
  270. (r21 (matrix-ref M 1 0)) (r22 (matrix-ref M 1 1)) (r23 (matrix-ref M 1 2))
  271. (r31 (matrix-ref M 2 0)) (r32 (matrix-ref M 2 1)) (r33 (matrix-ref M 2 2)))
  272. (let ((q0^2 (g:* 1/4 (g:+ 1 r11 r22 r33)))
  273. (q1^2 (g:* 1/4 (g:+ 1 r11 (g:- r22) (g:- r33))))
  274. (q2^2 (g:* 1/4 (g:+ 1 (g:- r11) r22 (g:- r33))))
  275. (q3^2 (g:* 1/4 (g:+ 1 (g:- r11) (g:- r22) r33)))
  276. (q0q1 (g:* 1/4 (g:- r32 r23)))
  277. (q0q2 (g:* 1/4 (g:- r13 r31)))
  278. (q0q3 (g:* 1/4 (g:- r21 r12)))
  279. (q1q2 (g:* 1/4 (g:+ r12 r21)))
  280. (q1q3 (g:* 1/4 (g:+ r13 r31)))
  281. (q2q3 (g:* 1/4 (g:+ r23 r32))))
  282. ;; If numerical, choose largest of squares.
  283. ;; If symbolic, choose nonzero square.
  284. (let ((q0 (g:sqrt q0^2)))
  285. (let ((q1 (g:/ q0q1 q0))
  286. (q2 (g:/ q0q2 q0))
  287. (q3 (g:/ q0q3 q0)))
  288. (quaternion q0 q1 q2 q3))))))
  289. |#
  290. ;;; Expanded Matt Mason method.
  291. (define (rotation-matrix->quaternion M)
  292. ;; (assert (orthogonal-matrix? M))
  293. ;; returns a unit quaternion
  294. (let ((r11 (matrix-ref M 0 0)) (r12 (matrix-ref M 0 1)) (r13 (matrix-ref M 0 2))
  295. (r21 (matrix-ref M 1 0)) (r22 (matrix-ref M 1 1)) (r23 (matrix-ref M 1 2))
  296. (r31 (matrix-ref M 2 0)) (r32 (matrix-ref M 2 1)) (r33 (matrix-ref M 2 2)))
  297. (let ((q0^2 (g:* 1/4 (g:+ 1 r11 r22 r33)))
  298. (q1^2 (g:* 1/4 (g:+ 1 r11 (g:- r22) (g:- r33))))
  299. (q2^2 (g:* 1/4 (g:+ 1 (g:- r11) r22 (g:- r33))))
  300. (q3^2 (g:* 1/4 (g:+ 1 (g:- r11) (g:- r22) r33)))
  301. (q0q1 (g:* 1/4 (g:- r32 r23)))
  302. (q0q2 (g:* 1/4 (g:- r13 r31)))
  303. (q0q3 (g:* 1/4 (g:- r21 r12)))
  304. (q1q2 (g:* 1/4 (g:+ r12 r21)))
  305. (q1q3 (g:* 1/4 (g:+ r13 r31)))
  306. (q2q3 (g:* 1/4 (g:+ r23 r32))))
  307. (let ((q0^2s (careful-simplify q0^2))
  308. (q1^2s (careful-simplify q1^2))
  309. (q2^2s (careful-simplify q2^2))
  310. (q3^2s (careful-simplify q3^2)))
  311. (cond ((and (number? q0^2s) (number? q1^2s)
  312. (number? q2^2s) (number? q3^2s))
  313. (cond ((>= q0^2s (max q1^2s q2^2s q3^2s))
  314. (let ((q0 (sqrt q0^2s)))
  315. (let ((q1 (g:/ q0q1 q0))
  316. (q2 (g:/ q0q2 q0))
  317. (q3 (g:/ q0q3 q0)))
  318. (quaternion q0 q1 q2 q3))))
  319. ((>= q1^2s (max q0^2s q2^2s q3^2s))
  320. (let ((q1 (sqrt q1^2s)))
  321. (let ((q0 (g:/ q0q1 q1))
  322. (q2 (g:/ q1q2 q1))
  323. (q3 (g:/ q1q3 q1)))
  324. (quaternion q0 q1 q2 q3))))
  325. ((>= q2^2s (max q0^2s q1^2s q3^2s))
  326. (let ((q2 (sqrt q2^2s)))
  327. (let ((q0 (g:/ q0q2 q2))
  328. (q1 (g:/ q1q2 q2))
  329. (q3 (g:/ q2q3 q2)))
  330. (quaternion q0 q1 q2 q3))))
  331. (else
  332. (let ((q3 (sqrt q3^2s)))
  333. (let ((q0 (g:/ q0q3 q3))
  334. (q1 (g:/ q1q3 q3))
  335. (q2 (g:/ q2q3 q3)))
  336. (quaternion q0 q1 q2 q3))))))
  337. ((not (and (number? q0^2s) (zero? q0^2s)))
  338. (let ((q0 (g:sqrt q0^2)))
  339. (let ((q1 (g:/ q0q1 q0))
  340. (q2 (g:/ q0q2 q0))
  341. (q3 (g:/ q0q3 q0)))
  342. (quaternion q0 q1 q2 q3))))
  343. ((not (and (number? q1^2s) (zero? q1^2s)))
  344. (let ((q1 (g:sqrt q1^2)))
  345. (let ((q0 0)
  346. (q2 (g:/ q1q2 q1))
  347. (q3 (g:/ q1q3 q1)))
  348. (quaternion q0 q1 q2 q3))))
  349. ((not (and (number? q2^2s) (zero? q2^2s)))
  350. (let ((q2 (g:sqrt q2^2)))
  351. (let ((q0 0)
  352. (q1 0)
  353. (q3 (g:/ q2q3 q2)))
  354. (quaternion q0 q1 q2 q3))))
  355. (else
  356. (quaternion 0 0 0 0)))))))
  357. (define q:rotation-matrix-> rotation-matrix->quaternion)
  358. #|
  359. (let ((M (* (rotate-z-matrix 0.1)
  360. (rotate-x-matrix 0.2)
  361. (rotate-z-matrix 0.3))))
  362. (- (rotation-matrix->quaternion-mason M)
  363. (rotation-matrix->quaternion M)))
  364. #|
  365. (quaternion 0. 0. 1.734723475976807e-18 0.)
  366. |#
  367. |#
  368. (define (quaternion->rotation-matrix q)
  369. (assert (quaternion? q))
  370. ;;(assert (q:unit? q))
  371. ;; This assertion is really:
  372. (let* ((vv (quaternion->vector q))
  373. (v (g:simplify (v:dot-product vv vv))))
  374. (assume! `(= ,v 1) 'quaternion->rotation-matrix))
  375. (let ((q0 (quaternion-ref q 0)) (q1 (quaternion-ref q 1))
  376. (q2 (quaternion-ref q 2)) (q3 (quaternion-ref q 3)))
  377. (let ((m^2 (g:+ (g:expt q0 2) (g:expt q1 2)
  378. (g:expt q2 2) (g:expt q3 2))))
  379. (matrix-by-rows
  380. (list (g:/ (g:+ (g:expt q0 2)
  381. (g:expt q1 2)
  382. (g:* -1 (g:expt q2 2))
  383. (g:* -1 (g:expt q3 2)))
  384. m^2)
  385. (g:/ (g:* 2 (g:- (g:* q1 q2) (g:* q0 q3)))
  386. m^2)
  387. (g:/ (g:* 2 (g:+ (g:* q1 q3) (g:* q0 q2)))
  388. m^2))
  389. (list (g:/ (g:* 2 (g:+ (g:* q1 q2) (g:* q0 q3)))
  390. m^2)
  391. (g:/ (g:+ (g:expt q0 2)
  392. (g:* -1 (g:expt q1 2))
  393. (g:expt q2 2)
  394. (g:* -1 (g:expt q3 2)))
  395. m^2)
  396. (g:/ (g:* 2 (g:- (g:* q2 q3) (g:* q0 q1)))
  397. m^2))
  398. (list (g:/ (g:* 2 (g:- (g:* q1 q3) (g:* q0 q2)))
  399. m^2)
  400. (g:/ (g:* 2 (g:+ (g:* q2 q3) (g:* q0 q1)))
  401. m^2)
  402. (g:/ (g:+ (g:expt q0 2)
  403. (g:* -1 (g:expt q1 2))
  404. (g:* -1 (g:expt q2 2))
  405. (g:expt q3 2))
  406. m^2))))))
  407. (define q:->rotation-matrix quaternion->rotation-matrix)
  408. #|
  409. (let ((theta 'theta) (v (up 'x 'y 'z)))
  410. (let ((axis (v:make-unit v)))
  411. (let ((result
  412. ((compose quaternion->angle-axis
  413. rotation-matrix->quaternion
  414. quaternion->rotation-matrix
  415. angle-axis->quaternion)
  416. theta axis)))
  417. (up (- (car result) theta)
  418. (- (cadr result) axis)))))
  419. #|
  420. (up 0 (up 0 0 0))
  421. |#
  422. ;;; But look at (show-notes) to see the assumptions.
  423. ;;; Indeed:
  424. (let ((theta -1) (v (up 1 2 3)))
  425. (let ((axis (v:make-unit v)))
  426. (let ((result
  427. ((compose quaternion->angle-axis
  428. rotation-matrix->quaternion
  429. quaternion->rotation-matrix
  430. angle-axis->quaternion)
  431. theta axis)))
  432. (up (- (car result) theta)
  433. (- (cadr result) axis)))))
  434. #|
  435. (up 2.
  436. (up -.5345224838248488
  437. -1.0690449676496976
  438. -1.6035674514745464))
  439. |#
  440. |#
  441. (define %kernel-quaternion-dummy-1
  442. (begin
  443. (assign-operation 'type q:type quaternion?)
  444. (assign-operation 'type-predicate q:type-predicate quaternion?)
  445. (assign-operation 'arity q:arity quaternion?)
  446. (assign-operation 'inexact? q:inexact? quaternion?)
  447. (assign-operation 'zero-like q:zero-like quaternion?)
  448. (assign-operation 'zero? q:zero? quaternion?)
  449. (assign-operation 'negate q:negate quaternion?)
  450. (assign-operation 'magnitude q:magnitude quaternion?)
  451. (assign-operation 'conjugate q:conjugate quaternion?)
  452. (assign-operation 'invert q:invert quaternion?)
  453. (assign-operation 'real-part q:real-part quaternion?)
  454. (assign-operation 'exp q:exp quaternion?)
  455. (assign-operation 'log q:log quaternion?)
  456. (assign-operation '= q:= quaternion? quaternion?)
  457. (assign-operation '+ quaternion+quaternion quaternion? quaternion?)
  458. (assign-operation '- quaternion-quaternion quaternion? quaternion?)
  459. (assign-operation '* quaternion*quaternion quaternion? quaternion?)
  460. (assign-operation '* scalar*quaternion scalar? quaternion?)
  461. (assign-operation '* quaternion*scalar quaternion? scalar?)
  462. (assign-operation '/ quaternion/scalar quaternion? scalar?)
  463. (assign-operation '/ quaternion/quaternion quaternion? quaternion?)
  464. (assign-operation 'apply q:apply quaternion? any?)
  465. (assign-operation 'partial-derivative q:partial-derivative quaternion? any?)))