system.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. ;;;; Unit systems
  21. (define* (define-unit-system system-name #:rest base-units)
  22. (if (environment-bound? scmutils-base-environment system-name)
  23. (write-line `(clobbering ,system-name)))
  24. (let ((n (length base-units)))
  25. (let ((base-specs
  26. (map (lambda (base-spec i)
  27. (let* ((unit-name (car base-spec))
  28. (exponents
  29. (make-initialized-vector n
  30. (lambda (j) (if (fix:= i j) 1 0))))
  31. (unit (make-unit system-name exponents 1)))
  32. (if (environment-bound? scmutils-base-environment
  33. unit-name)
  34. (write-line `(clobbering ,unit-name)))
  35. (environment-define scmutils-base-environment
  36. unit-name
  37. unit)
  38. (append base-spec (list unit))))
  39. base-units
  40. (iota n))))
  41. (environment-define scmutils-base-environment
  42. system-name
  43. (list '*unit-system*
  44. system-name
  45. base-specs ;base units
  46. '() ;derived units
  47. '() ;additional units
  48. ))))
  49. system-name)
  50. (define (unit-system? system)
  51. (and (pair? system)
  52. (eq? (car system) '*unit-system*)))
  53. (define (unit-system-name system)
  54. (cadr system))
  55. (define (base-units system)
  56. (caddr system))
  57. (define (derived-units system)
  58. (cadddr system))
  59. (define (alternate-units system)
  60. (car (cddddr system)))
  61. ;;; Data may be entered and results may be presented in derived units.
  62. (define* (define-derived-unit system unit-name tex description content
  63. #:optional scale-factor)
  64. (assert (unit-system? system))
  65. (if (environment-bound? scmutils-base-environment unit-name)
  66. (write-line `(clobbering ,unit-name)))
  67. (if (default-object? scale-factor)
  68. (set! scale-factor 1))
  69. (set! content
  70. (make-unit (unit-system-name system)
  71. (unit-exponents content)
  72. (* (expression scale-factor) (unit-scale content))))
  73. (let ((unit-spec (list unit-name tex description content)))
  74. (define-derived-unit! system unit-spec)
  75. (environment-define scmutils-base-environment unit-name content)
  76. unit-name))
  77. (define (define-derived-unit! system unit-spec)
  78. (set-car! (cdddr system)
  79. (append (cadddr system)
  80. (list unit-spec))))
  81. ;;; Data may be entered in additional units but results will not be
  82. ;;; presented in additional units.
  83. (define* (define-additional-unit system unit-name tex description content
  84. #:optional scale-factor)
  85. (assert (unit-system? system))
  86. (if (environment-bound? scmutils-base-environment unit-name)
  87. (write-line `(clobbering ,unit-name)))
  88. (if (default-object? scale-factor)
  89. (set! scale-factor 1))
  90. (set! content
  91. (make-unit (unit-system-name system)
  92. (unit-exponents content)
  93. (* (expression scale-factor) (unit-scale content))))
  94. (let ((unit-spec (list unit-name tex description content)))
  95. (define-additional-unit! system unit-spec)
  96. (environment-define scmutils-base-environment unit-name content)
  97. unit-name))
  98. (define (define-additional-unit! system unit-spec)
  99. (set-car! (cddddr system)
  100. (append (car (cddddr system))
  101. (list unit-spec))))
  102. (define *multiplier-names* '())
  103. (define (define-multiplier name tex-string log-value)
  104. (if (environment-bound? scmutils-base-environment name)
  105. (write-line `(clobbering ,name)))
  106. (set! *multiplier-names*
  107. (cons (list name tex-string log-value)
  108. *multiplier-names*))
  109. (environment-define scmutils-base-environment
  110. name
  111. (expt 10 log-value)))
  112. (define *numerical-constants* '())
  113. (define* (define-constant name tex-string description value units
  114. #:optional uncertainty)
  115. (if (environment-bound? scmutils-base-environment name)
  116. (write-line `(clobbering ,name)))
  117. (let ((constant (literal-number name)))
  118. (cond ((with-units? value)
  119. (assert (same-units? (u:units value) units))))
  120. (set! value (g:simplify (u:value value)))
  121. (add-property! constant 'name name)
  122. (add-property! constant 'numerical-value value)
  123. (add-property! constant 'units units)
  124. (add-property! constant 'tex-string tex-string)
  125. (add-property! constant 'description description)
  126. (if (real? value) (declare-known-reals name))
  127. (if (not (default-object? uncertainty))
  128. (add-property! constant 'uncertainty uncertainty))
  129. (set! *numerical-constants* (cons constant *numerical-constants*))
  130. (environment-define scmutils-base-environment
  131. name
  132. (with-units value units))
  133. name))
  134. (define* (numerical-constants #:optional units? constants)
  135. (if (default-object? units?) (set! units? #t))
  136. (if (default-object? constants) (set! constants *numerical-constants*))
  137. (for-each (lambda (c)
  138. (environment-assign!
  139. scmutils-base-environment
  140. (get-property c 'name)
  141. (if units?
  142. (with-units (get-property c 'numerical-value)
  143. (get-property c 'units))
  144. (g:* (get-property c 'numerical-value)
  145. (unit-scale (get-property c 'units))))))
  146. constants))
  147. (define* (symbolic-constants #:optional units? constants)
  148. (if (default-object? units?) (set! units? #t))
  149. (if (default-object? constants) (set! constants *numerical-constants*))
  150. (for-each (lambda (c)
  151. (environment-assign!
  152. scmutils-base-environment
  153. (get-property c 'name)
  154. (if units?
  155. (with-units (get-property c 'name)
  156. (get-property c 'units))
  157. (g:* (get-property c 'name)
  158. (unit-scale (get-property c 'units))))))
  159. constants))
  160. (define (get-constant-data name)
  161. (find-matching-item *numerical-constants*
  162. (lambda (c) (eq? (get-property c 'name) name))))
  163. ;;; & is used to attach units to a number, or to check that a number
  164. ;;; has the given units.
  165. (define* (& value u1 #:optional u2)
  166. (let ((units (if (default-object? u2) u1 u2))
  167. (scale (if (default-object? u2) 1 u1)))
  168. (assert (and (not (units? value)) (number? scale) (units? units)))
  169. (if (with-units? value)
  170. (if (equal? (unit-exponents units)
  171. (unit-exponents (u:units value)))
  172. value
  173. (error "Units do not match: &" value units))
  174. (with-units (g:* scale (unit-scale units) value)
  175. (make-unit (unit-system units)
  176. (unit-exponents units)
  177. 1)))))
  178. (define *unit-constructor* '&)
  179. ;;; FBE: we comment the following definitions and move them after we
  180. ;;; create the 'generic-environment'.
  181. ;; (define unit-environment generic-environment)
  182. ;; (define (express-as num target-unit-expression)
  183. ;; (let ((target-unit-expression-value
  184. ;; (eval target-unit-expression unit-environment)))
  185. ;; (cond ((with-units? target-unit-expression-value)
  186. ;; (let ((target-val (u:value target-unit-expression-value))
  187. ;; (target-units (u:units target-unit-expression-value)))
  188. ;; (express-in-given-units (g:/ num target-val)
  189. ;; target-units
  190. ;; target-unit-expression)))
  191. ;; ((units? target-unit-expression-value)
  192. ;; (express-in-given-units num
  193. ;; target-unit-expression-value
  194. ;; target-unit-expression))
  195. ;; (else num))))
  196. (define (express-in-given-units num target-unit target-unit-expression)
  197. (cond ((with-units? num)
  198. (let ((value (g:* (unit-scale (u:units num)) (u:value num)))
  199. (vect (unit-exponents (u:units num))))
  200. (if (not (equal? vect (unit-exponents target-unit)))
  201. (error "Cannot express in given units"
  202. num target-unit target-unit-expression))
  203. (list *unit-constructor*
  204. (g:/ (expression value) (unit-scale target-unit))
  205. target-unit-expression)))
  206. ((units? num)
  207. (list *unit-constructor*
  208. (g:/ (unit-scale num) (unit-scale target-unit))
  209. target-unit-expression))
  210. (else num)))
  211. (define (with-units->expression system num)
  212. (assert (unit-system? system))
  213. (cond ((with-units? num)
  214. (let ((value (g:* (unit-scale (u:units num)) (u:value num)))
  215. (vect (unit-exponents (u:units num))))
  216. (make-unit-description value vect system)))
  217. ((units? num)
  218. (make-unit-description (unit-scale num)
  219. (unit-exponents num)
  220. system))
  221. (else num)))
  222. (define (make-unit-description value exponent-vector system)
  223. (let ((available
  224. (or (find-unit-description exponent-vector
  225. (base-units system))
  226. (find-unit-description exponent-vector
  227. (derived-units system)))))
  228. (if available
  229. (let ((unit-name (car available))
  230. (scale (unit-scale (list-ref available 3))))
  231. (list *unit-constructor*
  232. (g:simplify (g:/ value scale))
  233. unit-name))
  234. (list *unit-constructor*
  235. (g:simplify value)
  236. (unit-expresson (vector->list exponent-vector)
  237. (map car (base-units system)))))))
  238. (define (find-unit-description vect ulist)
  239. (find-matching-item ulist
  240. (lambda (entry)
  241. (equal? (unit-exponents (list-ref entry 3))
  242. vect))))
  243. (define (find-unit-name vect ulist)
  244. (let ((v (find-unit-description vect ulist)))
  245. (if v (car v) #f)))
  246. (define (unit-expresson exponents base-unit-names)
  247. (cons '*
  248. (apply append
  249. (map (lambda (exponent base-name)
  250. (cond ((g:zero? exponent) '())
  251. ((g:one? exponent) (list base-name))
  252. (else
  253. (list (list 'expt base-name exponent)))))
  254. exponents
  255. base-unit-names))))
  256. #|
  257. (with-units->expression SI &foot)
  258. ;Value: (& .3048 &meter)
  259. (with-units->expression SI (& 2 &foot))
  260. ;Value: (& .6096 &meter)
  261. (with-units->expression SI (/ (* :k (& 300 &kelvin)) :e))
  262. ;Value: (& .02585215707677003 &volt)
  263. (with-units->expression SI :c)
  264. ;Value: (& 299792458. (* &meter (expt &second -1)))
  265. (with-units->expression SI :h)
  266. ;Value: (& 6.6260755e-34 (* (expt &meter 2) &kilogram (expt &second -1)))
  267. |#
  268. #|
  269. ;;; Work in progress
  270. (define (foosh x)
  271. (let* ((logscale (round->exact (log10 x)))
  272. (scale (expt 10 logscale))
  273. )
  274. (list (/ x scale) scale)
  275. ))
  276. (foosh 3/1000)
  277. #|
  278. (3 1/1000)
  279. |#
  280. |#