comparison sicm/bk/utils.org @ 2:b4de894a1e2e

initial import
author Robert McIntyre <rlm@mit.edu>
date Fri, 28 Oct 2011 00:03:05 -0700
parents
children
comparison
equal deleted inserted replaced
1:8d8278e09888 2:b4de894a1e2e
1 #+TITLE:Building a Classical Mechanics Library in Clojure
2 #+author: Robert McIntyre & Dylan Holmes
3 #+EMAIL: rlm@mit.edu
4 #+MATHJAX: align:"left" mathml:t path:"../MathJax/MathJax.js"
5 #+STYLE: <link rel="stylesheet" type="text/css" href="../css/aurellem.css" />
6 #+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
7 #+SETUPFILE: ../templates/level-0.org
8 #+INCLUDE: ../templates/level-0.org
9 #+BABEL: :noweb yes :results silent
10
11 * Generic Arithmetic
12
13 #+srcname: generic-arithmetic
14 #+begin_src clojure
15 (ns sicm.utils)
16 (in-ns 'sicm.utils)
17
18
19
20 (defn all-equal? [coll]
21 (if (empty? (rest coll)) true
22 (and (= (first coll) (second coll))
23 (recur (rest coll)))))
24
25
26 (defprotocol Arithmetic
27 (zero [this])
28 (one [this])
29 (negate [this])
30 (invert [this])
31 (conjugate [this]))
32
33 (defn zero? [x]
34 (= x (zero x)))
35 (defn one? [x]
36 (= x (one x)))
37
38
39
40 (extend-protocol Arithmetic
41 java.lang.Number
42 (zero [x] 0)
43 (one [x] 1)
44 (negate [x] (- x))
45 (invert [x] (/ x))
46 )
47
48 (extend-protocol Arithmetic
49 clojure.lang.IFn
50 (one [f] identity)
51 (negate [f] (comp negate f))
52 (invert [f] (comp invert f)))
53
54
55 (extend-protocol Arithmetic
56 clojure.lang.Seqable
57 (zero [this] (map zero this))
58 (one [this] (map one this))
59 (invert [this] (map invert this))
60 (negate [this] (map negate this)))
61
62
63 (defn ordered-like
64 "Create a comparator using the sorted collection as an
65 example. Elements not in the sorted collection are sorted to the
66 end."
67 [sorted-coll]
68 (let [
69 sorted-coll? (set sorted-coll)
70 ascending-pair?
71 (set(reduce concat
72 (map-indexed
73 (fn [n x]
74 (map #(vector x %) (nthnext sorted-coll n)))
75 sorted-coll)))]
76 (fn [x y]
77 (cond
78 (= x y) 0
79 (ascending-pair? [x y]) -1
80 (ascending-pair? [y x]) 1
81 (sorted-coll? x) -1
82 (sorted-coll? y) 1))))
83
84
85
86 (def type-precedence
87 (ordered-like [incanter.Matrix]))
88
89 (defmulti add
90 (fn [x y]
91 (sort type-precedence [(type x)(type y)])))
92
93 (defmulti multiply
94 (fn [x y]
95 (sort type-precedence [(type x) (type y)])))
96
97 (defmethod add [java.lang.Number java.lang.Number] [x y] (+ x y))
98 (defmethod multiply [java.lang.Number java.lang.Number] [x y] (* x y))
99
100 (defmethod multiply [incanter.Matrix java.lang.Integer] [x y]
101 (let [args (sort #(type-precedence (type %1)(type %2)) [x y])
102 matrix (first args)
103 scalar (second args)]
104 (incanter.core/matrix (map (partial map (partial multiply scalar)) matrix))))
105
106 #+end_src
107
108
109 * Useful Data Types
110
111 ** Complex Numbers
112 #+srcname: complex-numbers
113 #+begin_src clojure
114 (in-ns 'sicm.utils)
115
116 (defprotocol Complex
117 (real-part [z])
118 (imaginary-part [z])
119 (magnitude-squared [z])
120 (angle [z])
121 (conjugate [z])
122 (norm [z]))
123
124 (defn complex-rectangular
125 "Define a complex number with the given real and imaginary
126 components."
127 [re im]
128 (reify Complex
129 (real-part [z] re)
130 (imaginary-part [z] im)
131 (magnitude-squared [z] (+ (* re re) (* im im)))
132 (angle [z] (java.lang.Math/atan2 im re))
133 (conjugate [z] (complex-rectangular re (- im)))
134
135 Arithmetic
136 (zero [z] (complex-rectangular 0 0))
137 (one [z] (complex-rectangular 1 0))
138 (negate [z] (complex-rectangular (- re) (- im)))
139 (invert [z] (complex-rectangular
140 (/ re (magnitude-squared z))
141 (/ (- im) (magnitude-squared z))))
142
143 Object
144 (toString [_]
145 (if (and (zero? re) (zero? im)) (str 0)
146 (str
147 (if (not(zero? re))
148 re)
149 (if ((comp not zero?) im)
150 (str
151 (if (neg? im) "-" "+")
152 (if ((comp not one?) (java.lang.Math/abs im))
153 (java.lang.Math/abs im))
154 "i")))))))
155
156 (defn complex-polar
157 "Define a complex number with the given magnitude and angle."
158 [mag ang]
159 (reify Complex
160 (magnitude-squared [z] (* mag mag))
161 (angle [z] angle)
162 (real-part [z] (* mag (java.lang.Math/cos ang)))
163 (imaginary-part [z] (* mag (java.lang.Math/sin ang)))
164 (conjugate [z] (complex-polar mag (- ang)))
165
166 Arithmetic
167 (zero [z] (complex-polar 0 0))
168 (one [z] (complex-polar 1 0))
169 (negate [z] (complex-polar (- mag) ang))
170 (invert [z] (complex-polar (/ mag) (- ang)))
171
172 Object
173 (toString [_] (str mag " * e^(i" ang")"))
174 ))
175
176
177 ;; Numbers are complex quantities
178
179 (extend-protocol Complex
180 java.lang.Number
181 (real-part [x] x)
182 (imaginary-part [x] 0)
183 (magnitude [x] x)
184 (angle [x] 0)
185 (conjugate [x] x))
186
187
188 #+end_src
189
190
191
192 ** Tuples and Tensors
193
194 A tuple is a vector which is spinable\mdash{}it can be either /spin
195 up/ or /spin down/. (Covariant, contravariant; dual vectors)
196 #+srcname: tuples
197 #+begin_src clojure
198 (in-ns 'sicm.utils)
199
200 (defprotocol Spinning
201 (up? [this])
202 (down? [this]))
203
204 (defn spin
205 "Returns the spin of the Spinning s, either :up or :down"
206 [#^Spinning s]
207 (cond (up? s) :up (down? s) :down))
208
209
210 (deftype Tuple
211 [spin coll]
212 clojure.lang.Seqable
213 (seq [this] (seq (.coll this)))
214 clojure.lang.Counted
215 (count [this] (count (.coll this))))
216
217 (extend-type Tuple
218 Spinning
219 (up? [this] (= ::up (.spin this)))
220 (down? [this] (= ::down (.spin this))))
221
222 (defmethod print-method Tuple
223 [o w]
224 (print-simple (str (if (up? o) 'u 'd) (.coll o)) w))
225
226
227
228 (defn up
229 "Create a new up-tuple containing the contents of coll."
230 [coll]
231 (Tuple. ::up coll))
232
233 (defn down
234 "Create a new down-tuple containing the contents of coll."
235 [coll]
236 (Tuple. ::down coll))
237
238
239 #+end_src
240
241 *** Contraction
242 Contraction is a binary operation that you can apply to compatible
243 tuples. Tuples are compatible for contraction if they have the same
244 length and opposite spins, and if the corresponding items in each
245 tuple are both numbers or both compatible tuples.
246
247 #+srcname: tuples-2
248 #+begin_src clojure
249 (in-ns 'sicm.utils)
250
251 (defn numbers?
252 "Returns true if all arguments are numbers, else false."
253 [& xs]
254 (every? number? xs))
255
256 (defn contractible?
257 "Returns true if the tuples a and b are compatible for contraction,
258 else false. Tuples are compatible if they have the same number of
259 components, they have opposite spins, and their elements are
260 pairwise-compatible."
261 [a b]
262 (and
263 (isa? (type a) Tuple)
264 (isa? (type b) Tuple)
265 (= (count a) (count b))
266 (not= (spin a) (spin b))
267
268 (not-any? false?
269 (map #(or
270 (numbers? %1 %2)
271 (contractible? %1 %2))
272 a b))))
273
274
275
276 (defn contract
277 "Contracts two tuples, returning the sum of the
278 products of the corresponding items. Contraction is recursive on
279 nested tuples."
280 [a b]
281 (if (not (contractible? a b))
282 (throw
283 (Exception. "Not compatible for contraction."))
284 (reduce +
285 (map
286 (fn [x y]
287 (if (numbers? x y)
288 (* x y)
289 (contract x y)))
290 a b))))
291
292 #+end_src
293
294 *** Matrices
295 #+srcname: matrices
296 #+begin_src clojure
297 (in-ns 'sicm.utils)
298 (require 'incanter.core) ;; use incanter's fast matrices
299
300 (defprotocol Matrix
301 (rows [matrix])
302 (cols [matrix])
303 (diagonal [matrix])
304 (trace [matrix])
305 (determinant [matrix])
306 (transpose [matrix])
307 (conjugate [matrix])
308 )
309
310 (extend-protocol Matrix
311 incanter.Matrix
312 (rows [rs] (map down (apply map vector (apply map vector rs))))
313 (cols [rs] (map up (apply map vector rs)))
314 (diagonal [matrix] (incanter.core/diag matrix) )
315 (determinant [matrix] (incanter.core/det matrix))
316 (trace [matrix] (incanter.core/trace matrix))
317 (transpose [matrix] (incanter.core/trans matrix))
318 )
319
320 (defn count-rows [matrix]
321 ((comp count rows) matrix))
322
323 (defn count-cols [matrix]
324 ((comp count cols) matrix))
325
326 (defn square? [matrix]
327 (= (count-rows matrix) (count-cols matrix)))
328
329 (defn identity-matrix
330 "Define a square matrix of size n-by-n with 1s along the diagonal and
331 0s everywhere else."
332 [n]
333 (incanter.core/identity-matrix n))
334
335
336
337
338
339 (defn matrix-by-rows
340 "Define a matrix by giving its rows."
341 [& rows]
342 (if
343 (not (all-equal? (map count rows)))
344 (throw (Exception. "All rows in a matrix must have the same number of elements."))
345 (incanter.core/matrix (vec rows))))
346
347 (defn matrix-by-cols
348 "Define a matrix by giving its columns"
349 [& cols]
350 (if (not (all-equal? (map count cols)))
351 (throw (Exception. "All columns in a matrix must have the same number of elements."))
352 (incanter.core/matrix (vec (apply map vector cols)))))
353
354 (defn identity-matrix
355 "Define a square matrix of size n-by-n with 1s along the diagonal and
356 0s everywhere else."
357 [n]
358 (incanter.core/identity-matrix n))
359
360
361
362 (extend-protocol Arithmetic
363 incanter.Matrix
364 (one [matrix]
365 (if (square? matrix)
366 (identity-matrix (count-rows matrix))
367 (throw (Exception. "Non-square matrices have no multiplicative unit."))))
368 (zero [matrix]
369 (apply matrix-by-rows (map zero (rows matrix))))
370 (negate [matrix]
371 (apply matrix-by-rows (map negate (rows matrix))))
372 (invert [matrix]
373 (incanter.core/solve matrix)))
374
375
376
377 (defmulti coerce-to-matrix
378 "Converts x into a matrix, if possible."
379 type)
380
381 (defmethod coerce-to-matrix incanter.Matrix [x] x)
382 (defmethod coerce-to-matrix Tuple [x]
383 (if (apply numbers? (seq x))
384 (if (up? x)
385 (matrix-by-cols (seq x))
386 (matrix-by-rows (seq x)))
387 (throw (Exception. "Non-numerical tuple cannot be converted into a matrix."))))
388
389
390
391
392
393 ;; (defn matrix-by-cols
394 ;; "Define a matrix by giving its columns."
395 ;; [& cols]
396 ;; (cond
397 ;; (not (all-equal? (map count cols)))
398 ;; (throw (Exception. "All columns in a matrix must have the same number of elements."))
399 ;; :else
400 ;; (reify Matrix
401 ;; (cols [this] (map up cols))
402 ;; (rows [this] (map down (apply map vector cols)))
403 ;; (diagonal [this] (map-indexed (fn [i col] (nth col i) cols)))
404 ;; (trace [this]
405 ;; (if (not= (count-cols this) (count-rows this))
406 ;; (throw (Exception.
407 ;; "Cannot take the trace of a non-square matrix."))
408 ;; (reduce + (diagonal this))))
409
410 ;; (determinant [this]
411 ;; (if (not= (count-cols this) (count-rows this))
412 ;; (throw (Exception.
413 ;; "Cannot take the determinant of a non-square matrix."))
414 ;; (reduce * (map-indexed (fn [i col] (nth col i)) cols))))
415 ;; )))
416
417 (extend-protocol Matrix Tuple
418 (rows [this] (if (down? this)
419 (list this)
420 (map (comp up vector) this)))
421
422 (cols [this] (if (up? this)
423 (list this)
424 (map (comp down vector) this))
425 ))
426
427 (defn matrix-multiply
428 "Returns the matrix resulting from the matrix multiplication of the given arguments."
429 ([A] (coerce-to-matrix A))
430 ([A B] (incanter.core/mmult (coerce-to-matrix A) (coerce-to-matrix B)))
431 ([M1 M2 & Ms] (reduce matrix-multiply (matrix-multiply M1 M2) Ms)))
432
433 #+end_src
434
435
436 ** Power Series
437 #+srcname power-series
438 #+begin_src clojure
439 (in-ns 'sicm.utils)
440 (use 'clojure.contrib.def)
441
442
443
444 (defn series-fn
445 "The function corresponding to the given power series."
446 [series]
447 (fn [x]
448 (reduce +
449 (map-indexed (fn[n x] (* (float (nth series n)) (float(java.lang.Math/pow (float x) n)) ))
450 (range 20)))))
451
452 (deftype PowerSeries
453 [coll]
454 clojure.lang.Seqable
455 (seq [this] (seq (.coll this)))
456
457 clojure.lang.Indexed
458 (nth [this n] (nth (.coll this) n 0))
459 (nth [this n not-found] (nth (.coll this) n not-found))
460
461 ;; clojure.lang.IFn
462 ;; (call [this] (throw(Exception.)))
463 ;; (invoke [this & args] args
464 ;; (let [f
465 ;; )
466 ;; (run [this] (throw(Exception.)))
467 )
468
469 (defn power-series
470 "Returns a power series with the items of the coll as its
471 coefficients. Trailing zeros are added to the end of coll."
472 [coeffs]
473 (PowerSeries. coeffs))
474
475 (defn power-series-indexed
476 "Returns a power series consisting of the result of mapping f to the non-negative integers."
477 [f]
478 (PowerSeries. (map f (range))))
479
480
481 (defn-memo nth-partial-sum
482 ([series n]
483 (if (zero? n) (first series)
484 (+ (nth series n)
485 (nth-partial-sum series (dec n))))))
486
487 (defn partial-sums [series]
488 (lazy-seq (map nth-partial-sum (range))))
489
490
491
492
493 (def cos-series
494 (power-series-indexed
495 (fn[n]
496 (if (odd? n) 0
497 (/
498 (reduce *
499 (reduce * (repeat (/ n 2) -1))
500 (range 1 (inc n)))
501 )))))
502
503 (def sin-series
504 (power-series-indexed
505 (fn[n]
506 (if (even? n) 0
507 (/
508 (reduce *
509 (reduce * (repeat (/ (dec n) 2) -1))
510 (range 1 (inc n)))
511 )))))
512
513 #+end_src
514
515
516 * Basic Utilities
517
518 ** Sequence manipulation
519
520 #+srcname: seq-manipulation
521 #+begin_src clojure
522 (ns sicm.utils)
523
524 (defn do-up
525 "Apply f to each number from low to high, presumably for
526 side-effects."
527 [f low high]
528 (doseq [i (range low high)] (f i)))
529
530 (defn do-down
531 "Apply f to each number from high to low, presumably for
532 side-effects."
533 [f high low]
534 (doseq [i (range high low -1)] (f i)))
535
536
537 (defn all-equal? [coll]
538 (if (empty? (rest coll)) true
539 (and (= (first coll) (second coll))
540 (recur (rest coll))))))
541
542 (defn multiplier
543 "Returns a function that 'multiplies' the members of a collection,
544 returning unit if called on an empty collection."
545 [multiply unit]
546 (fn [coll] ((partial reduce multiply unit) coll)))
547
548 (defn divider
549 "Returns a function that 'divides' the first element of a collection
550 by the 'product' of the rest of the collection."
551 [divide multiply invert unit]
552 (fn [coll]
553 (apply
554 (fn
555 ([] unit)
556 ([x] (invert x))
557 ([x y] (divide x y))
558 ([x y & zs] (divide x (reduce multiply y zs))))
559 coll)))
560
561 (defn left-circular-shift
562 "Remove the first element of coll, adding it to the end of coll."
563 [coll]
564 (concat (rest coll) (take 1 coll)))
565
566 (defn right-circular-shift
567 "Remove the last element of coll, adding it to the front of coll."
568 [coll]
569 (cons (last coll) (butlast coll)))
570 #+end_src
571
572
573
574
575 ** Ranges, Airity and Function Composition
576 #+srcname: arity
577 #+begin_src clojure
578 (in-ns 'sicm.utils)
579 (def infinity Double/POSITIVE_INFINITY)
580 (defn infinite? [x] (Double/isInfinite x))
581 (def finite? (comp not infinite?))
582
583 (defn arity-min
584 "Returns the smallest number of arguments f can take."
585 [f]
586 (apply
587 min
588 (map (comp alength #(.getParameterTypes %))
589 (filter (comp (partial = "invoke") #(.getName %))
590 (.getDeclaredMethods (class f))))))
591
592 (defn arity-max
593 "Returns the largest number of arguments f can take, possibly
594 Infinity."
595 [f]
596 (let [methods (.getDeclaredMethods (class f))]
597 (if (not-any? (partial = "doInvoke") (map #(.getName %) methods))
598 (apply max
599 (map (comp alength #(.getParameterTypes %))
600 (filter (comp (partial = "invoke") #(.getName %)) methods)))
601 infinity)))
602
603
604 (def ^{:arglists '([f])
605 :doc "Returns a two-element list containing the minimum and
606 maximum number of args that f can take."}
607 arity-interval
608 (juxt arity-min arity-max))
609
610
611
612 ;; --- intervals
613
614 (defn intersect
615 "Returns the interval of overlap between interval-1 and interval-2"
616 [interval-1 interval-2]
617 (if (or (empty? interval-1) (empty? interval-2)) []
618 (let [left (max (first interval-1) (first interval-2))
619 right (min (second interval-1) (second interval-2))]
620 (if (> left right) []
621 [left right]))))
622
623 (defn same-endpoints?
624 "Returns true if the left endpoint is the same as the right
625 endpoint."
626 [interval]
627 (= (first interval) (second interval)))
628
629 (defn naturals?
630 "Returns true if the left endpoint is 0 and the right endpoint is
631 infinite."
632 [interval]
633 (and (zero? (first interval))
634 (infinite? (second interval))))
635
636
637 (defn fan-in
638 "Returns a function that pipes its input to each of the gs, then
639 applies f to the list of results. Consequently, f must be able to
640 take a number of arguments equal to the number of gs."
641 [f & gs]
642 (fn [& args]
643 (apply f (apply (apply juxt gs) args))))
644
645 (defn fan-in
646 "Returns a function that pipes its input to each of the gs, then applies f to the list of results. The resulting function takes any number of arguments, but will fail if given arguments that are incompatible with any of the gs."
647 [f & gs]
648 (comp (partial apply f) (apply juxt gs)))
649
650
651
652 (defmacro airty-blah-sad [f n more?]
653 (let [syms (vec (map (comp gensym (partial str "x")) (range n)))
654 optional (gensym "xs")]
655 (if more?
656 `(fn ~(conj syms '& optional)
657 (apply ~f ~@syms ~optional))
658 `(fn ~syms (~f ~@syms)))))
659
660 (defmacro airt-whaa* [f n more?]
661 `(airty-blah-sad ~f ~n ~more?))
662
663
664
665
666 (defn fan-in*
667 "Returns a function that pipes its input to each of the gs, then
668 applies f to the list of results. Unlike fan-in, fan-in* strictly
669 enforces arity: it will fail if the gs do not have compatible
670 arities."
671 [f & gs]
672 (let [arity-in (reduce intersect (map arity-interval gs))
673 left (first arity-in)
674 right (second arity-in)
675 composite (fan-in f gs)
676 ]
677 (cond
678 (empty? arity-in)
679 (throw (Exception. "Cannot compose functions with incompatible arities."))
680
681 (not
682 (or (= left right)
683 (and (finite? left)
684 (= right infinity))))
685
686 (throw (Exception.
687 "Compose can only handle arities of the form [n n] or [n infinity]"))
688 :else
689 (airty-blah-sad composite left (= right infinity)))))
690
691
692
693 (defn compose-n "Compose any number of functions together."
694 ([] identity)
695 ([f] f)
696 ([f & fs]
697 (let [fns (cons f fs)]
698 (compose-bin (reduce fan-in (butlast fs)) (last fs))))
699 )
700
701
702
703
704
705
706 (defn iterated
707 ([f n id] (reduce comp id (repeat n f)))
708 ([f n] (reduce comp identity (repeat n f))))
709
710 (defn iterate-until-stable
711 "Repeatedly applies f to x, returning the first result that is close
712 enough to its predecessor."
713 [f close-enough? x]
714 (second (swank.util/find-first
715 (partial apply close-enough?)
716 (partition 2 1 (iterate f x)))))
717
718 (defn lexical< [x y]
719 (neg? (compare (str x) (str y))))
720
721
722 ;; do-up
723 ;; do-down
724 (def make-pairwise-test comparator)
725 ;;all-equal?
726 (def accumulation multiplier)
727 (def inverse-accumulation divider)
728 ;;left-circular-shift
729 ;;right-circular-shift
730 (def exactly-n? same-endpoints?)
731 (def any-number? naturals?)
732 ;; TODO compose
733 ;; TODO compose-n
734 ;; identity
735 (def compose-2 fan-in)
736 (def compose-bin fan-in*)
737 (def any? (constantly true))
738 (def none? (constantly false))
739 (def constant constantly)
740 (def joint-arity intersect)
741 (def a-reduce reduce)
742 ;; filter
743 (def make-map (partial partial map) )
744 (def bracket juxt)
745 ;; TODO apply-to-all
746 ;; TODO nary-combine
747 ;; TODO binary-combine
748 ;; TODO unary-combine
749 ;; iterated
750 ;; iterate-until-stable
751 (def make-function-of-vector (partial partial map))
752 (def make-function-of-arguments (fn [f] (fn [& args] (f args))))
753 (def alphaless lexical<)
754
755 #+end_src
756
757
758
759
760
761
762
763 :
764
765 * Numerical Methods
766 #+srcname: numerical-methods
767 #+begin_src clojure
768 (in-ns 'sicm.utils)
769 (import java.lang.Math)
770 (use 'clojure.contrib.def)
771
772 ;; ---- USEFUL CONSTANTS
773
774 (defn machine-epsilon
775 "Smallest value representable on your machine, as determined by
776 successively dividing a number in half until consecutive results are
777 indistinguishable."
778 []
779 (ffirst
780 (drop-while
781 (comp not zero? second)
782 (partition 2 1
783 (iterate (partial * 0.5) 1)))))
784
785
786 (def pi (Math/PI))
787 (def two-pi (* 2 pi))
788
789 (def eulers-gamma 0.5772156649015328606065)
790
791 (def phi (/ (inc (Math/sqrt 5)) 2))
792
793 (def ln2 (Math/log 2))
794 (def ln10 (Math/log 10))
795 (def exp10 #(Math/pow 10 %))
796 (def exp2 #(Math/pow 2 %))
797
798
799 ;;
800
801 ;; ---- ANGLES AND TRIGONOMETRY
802
803 (defn angle-restrictor
804 "Returns a function that ensures that angles lie in the specified interval of length two-pi."
805 [max-angle]
806 (let [min-angle (- max-angle two-pi)]
807 (fn [x]
808 (if (and
809 (<= min-angle x)
810 (< x max-angle))
811 x
812 (let [corrected-x (- x (* two-pi (Math/floor (/ x two-pi))))]
813 (if (< corrected-x max-angle)
814 corrected-x
815 (- corrected-x two-pi)))))))
816
817 (defn angle-restrict-pi
818 "Coerces angles to lie in the interval from -pi to pi."
819 [angle]
820 ((angle-restrictor pi) angle))
821
822 (defn angle-restrict-two-pi
823 "Coerces angles to lie in the interval from zero to two-pi"
824 [angle]
825 ((angle-restrictor two-pi) angle))
826
827
828
829
830 (defn invert [x] (/ x))
831 (defn negate [x] (- x))
832
833 (defn exp [x] (Math/exp x))
834
835 (defn sin [x] (Math/sin x))
836 (defn cos [x] (Math/cos x))
837 (defn tan [x] (Math/tan x))
838
839 (def sec (comp invert cos))
840 (def csc (comp invert sin))
841
842 (defn sinh [x] (Math/sinh x))
843 (defn cosh [x] (Math/cosh x))
844 (defn tanh [x] (Math/tanh x))
845
846 (def sech (comp invert cosh))
847 (def csch (comp invert sinh))
848
849
850 ;; ------------
851
852 (defn factorial
853 "Computes the factorial of the nonnegative integer n."
854 [n]
855 (if (neg? n)
856 (throw (Exception. "Cannot compute the factorial of a negative number."))
857 (reduce * 1 (range 1 (inc n)))))
858
859 (defn exact-quotient [n d] (/ n d))
860
861 (defn binomial-coefficient
862 "Computes the number of different ways to choose m elements from n."
863 [n m]
864 (assert (<= 0 m n))
865 (let [difference (- n m)]
866 (exact-quotient
867 (reduce * (range n (max difference m) -1 ))
868 (factorial (min difference m)))))
869
870 (defn-memo stirling-1
871 "Stirling numbers of the first kind: the number of permutations of n
872 elements with exactly m permutation cycles. "
873 [n k]
874 ;(assert (<= 1 k n))
875 (if (zero? n)
876 (if (zero? k) 1 0)
877 (+ (stirling-1 (dec n) (dec k))
878 (* (dec n) (stirling-1 (dec n) k)))))
879
880 (defn-memo stirling-2 ;;count-partitions
881 "Stirling numbers of the second kind: the number of ways to partition a set of n elements into k subsets."
882 [n k]
883 (cond
884 (= k 1) 1
885 (= k n) 1
886 :else (+ (stirling-2 (dec n) (dec k))
887 (* k (stirling-2 (dec n) k)))))
888
889 (defn harmonic-number [n]
890 (/ (stirling-1 (inc n) 2)
891 (factorial n)))
892
893
894 (defn sum
895 [f low high]
896 (reduce + (map f (range low (inc high)))))
897
898 #+end_src
899
900
901
902
903
904
905
906
907
908
909
910
911 * Differentiation
912
913 We compute derivatives by passing special *differential objects* $[x,
914 dx]$ through functions. Roughly speaking, applying a function $f$ to a
915 differential object \([x, dx]\) should produce a new differential
916 object $[f(x),\,Df(x)\cdot dx]$.
917
918 \([x,\,dx]\xrightarrow{\quad f \quad}[f(x),\,Df(x)\cdot dx]\)
919 Notice that you can obtain the derivative of $f$ from this
920 differential object, as it is the coefficient of the $dx$ term. Also,
921 as you apply successive functions using this rule, you get the
922 chain-rule answer you expect:
923
924 \([f(x),\,Df(x)\cdot dx]\xrightarrow{\quad g\quad} [gf(x),\,
925 Dgf(x)\cdot Df(x) \cdot dx ]\)
926
927 In order to generalize to multiple variables and multiple derivatives,
928 we use a *power series of differentials*, a sortred infinite sequence which
929 contains all terms like $dx\cdot dy$, $dx^2\cdot dy$, etc.
930
931
932 #+srcname:differential
933 #+begin_src clojure
934 (in-ns 'sicm.utils)
935 (use 'clojure.contrib.combinatorics)
936 (use 'clojure.contrib.generic.arithmetic)
937
938 (defprotocol DifferentialTerm
939 "Protocol for an infinitesimal quantity."
940 (coefficient [this])
941 (partials [this]))
942
943 (extend-protocol DifferentialTerm
944 java.lang.Number
945 (coefficient [this] this)
946 (partials [this] []))
947
948 (deftype DifferentialSeq
949 [terms]
950 clojure.lang.IPersistentCollection
951 (cons [this x]
952 (throw (Exception. x))
953 (DifferentialSeq. (cons x terms)))
954 ;; (seq [this] (seq terms))
955 (count [this] (count terms))
956 (empty [this] (empty? terms)))
957
958
959
960
961
962
963
964
965
966
967
968 (defn coerce-to-differential-seq [x]
969 (cond
970 (= (type x) DifferentialSeq) x
971 (satisfies? DifferentialTerm x) (DifferentialSeq. x)))
972
973
974 (defn differential-term
975 "Returns a differential term with the given coefficient and
976 partials. Coefficient may be any arithmetic object; partials must
977 be a list of non-negative integers."
978 [coefficient partials]
979 (reify DifferentialTerm
980 (partials [_] (set partials))
981 (coefficient [_] coefficient)))
982
983
984
985 (defn differential-seq*
986 ([coefficient partials]
987 (DifferentialSeq. [(differential-term coefficient partials)]))
988 ([coefficient partials & cps]
989 (if cps
990
991
992
993
994 (defn differential-seq
995 "Constructs a sequence of differential terms from a numerical
996 coefficient and a list of keys for variables. If no coefficient is supplied, uses 1."
997 ([variables] (differential-seq 1 variables))
998 ([coefficient variables & cvs]
999 (if (number? coefficient)
1000 (conj (assoc {} (apply sorted-set variables) coefficient)
1001 (if (empty? cvs)
1002 nil
1003 (apply differential-seq cvs)))
1004 (apply differential-seq 1 coefficient 1 variables cvs)
1005 )))
1006
1007
1008 (defn differential-add
1009 "Add two differential sequences by combining like terms."
1010 [dseq1 dseq2]
1011 (merge-with + dseq1 dseq2))
1012
1013 (defn differential-multiply
1014 "Multiply two differential sequences. The square of any differential variable is zero since differential variables are infinitesimally small."
1015 [dseq1 dseq2]
1016 (reduce
1017 (fn [m [[vars1 coeff1] [vars2 coeff2]]]
1018 (if (empty? (clojure.set/intersection vars1 vars2))
1019 (assoc m (clojure.set/union vars1 vars2) (* coeff1 coeff2))
1020 m))
1021 {}
1022 (clojure.contrib.combinatorics/cartesian-product
1023 dseq1
1024 dseq2)))
1025
1026
1027 (defn big-part
1028 "Returns the part of the differential sequence that is finite,
1029 i.e. not infinitely small."
1030 [dseq]
1031 (let
1032 [keys (sort-by count (keys dseq))
1033 smallest-var (last(last keys))]
1034 (apply hash-map
1035 (reduce concat
1036 (remove (comp smallest-var first) dseq)))))
1037
1038 (defn small-part
1039 "Returns the part of the differential sequence that is
1040 infinitesimal."
1041 [dseq]
1042 (let
1043 [keys (sort-by count (keys dseq))
1044 smallest-var (last(last keys))]
1045 (apply hash-map
1046 (reduce concat
1047 (filter (comp smallest-var first) dseq)))))
1048
1049 (defn big-part
1050 "Returns the 'finite' part of the differential sequence."
1051 [dseq]
1052 (let
1053 [keys (sort-by count (keys dseq))
1054 smallest-var (last (last keys))]
1055 (apply hash-map
1056 (reduce concat
1057 (filter (remove smallest-var first) dseq)
1058 ))))
1059
1060
1061 (defn small-part
1062 "Returns the 'infinitesimal' part of the differential sequence."
1063 [dseq]
1064 (let
1065 [keys (sort-by count (keys dseq))
1066 smallest-var (last (last keys))]
1067
1068 (apply hash-map
1069 (reduce concat
1070 (filter (comp smallest-var first) dseq)
1071 ))))
1072
1073 (defn linear-approximator
1074 "Returns the function that corresponds to unary-fn but which accepts and returns differential objects."
1075 ([unary-f dfdx]
1076 (fn F [dseq]
1077 (differential-add
1078 (unary-f (big-part dseq))
1079 (differential-multiply
1080 (dfdx (big-part dseq))
1081 (small-part dseq))))))
1082
1083
1084
1085
1086
1087
1088 ;; ;; A differential term consists of a numerical coefficient and a
1089 ;; ;; sorted
1090 ;; (defrecord DifferentialTerm [coefficient variables])
1091 ;; (defmethod print-method DifferentialTerm
1092 ;; [o w]
1093 ;; (print-simple
1094 ;; (apply str (.coefficient o)(map (comp (partial str "d") name) (.variables o)))
1095 ;; w))
1096
1097
1098 ;; (defn differential-seq
1099 ;; "Constructs a sequence of differential terms from a numerical
1100 ;; coefficient and a list of keywords for variables. If no coefficient is
1101 ;; supplied, uses 1."
1102 ;; ([variables] (differential-seq 1 variables))
1103 ;; ([coefficient variables]
1104 ;; (list
1105 ;; (DifferentialTerm. coefficient (apply sorted-set variables))))
1106 ;; ([coefficient variables & cvs]
1107 ;; (sort-by
1108 ;; #(vec(.variables %))
1109 ;; (concat (differential-seq coefficient variables) (apply differential-seq cvs)))))
1110
1111 #+end_src
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125 * Symbolic Manipulation
1126
1127 #+srcname:symbolic
1128 #+begin_src clojure
1129 (in-ns 'sicm.utils)
1130
1131 (deftype Symbolic [type expression]
1132 Object
1133 (equals [this that]
1134 (cond
1135 (= (.expression this) (.expression that)) true
1136 :else
1137 (Symbolic.
1138 java.lang.Boolean
1139 (list '= (.expression this) (.expression that)))
1140 )))
1141
1142
1143
1144
1145 (deftype AbstractSet [glyph membership-test])
1146 (defn member? [abstract-set x]
1147 ((.membership-test abstract-set) x))
1148
1149 ;; ------------ Some important AbstractSets
1150
1151
1152 (def Real
1153 (AbstractSet.
1154 'R
1155 (fn[x](number? x))))
1156
1157
1158 ;; ------------ Create new AbstractSets from existing ones
1159
1160 (defn abstract-product
1161 "Gives the cartesian product of abstract sets."
1162 ([sets]
1163 (if (= (count sets) 1) (first sets)
1164 (AbstractSet.
1165 (symbol
1166 (apply str
1167 (interpose 'x (map #(.glyph %) sets))))
1168 (fn [x]
1169 (and
1170 (coll? x)
1171 (= (count sets) (count x))
1172 (reduce #(and %1 %2)
1173 true
1174 (map #(member? %1 %2) sets x)))))))
1175 ([abstract-set n]
1176 (abstract-product (repeat n abstract-set))))
1177
1178
1179
1180 (defn abstract-up
1181 "Returns the abstract set of all up-tuples whose items belong to the
1182 corresponding abstract sets in coll."
1183 ([coll]
1184 (AbstractSet.
1185 (symbol (str "u["
1186 (apply str
1187 (interpose " "
1188 (map #(.glyph %) coll)))
1189 "]"))
1190 (fn [x]
1191 (and
1192 (satisfies? Spinning x)
1193 (up? x)
1194 (= (count coll) (count x))
1195 (reduce
1196 #(and %1 %2)
1197 true
1198 (map #(member? %1 %2) coll x))))))
1199 ([abstract-set n]
1200 (abstract-up (repeat n abstract-set))))
1201
1202
1203 (defn abstract-down
1204 "Returns the abstract set of all down-tuples whose items belong to the
1205 corresponding abstract sets in coll."
1206 ([coll]
1207 (AbstractSet.
1208 (symbol (str "d["
1209 (apply str
1210 (interpose " "
1211 (map #(.glyph %) coll)))
1212 "]"))
1213 (fn [x]
1214 (and
1215 (satisfies? Spinning x)
1216 (down? x)
1217 (= (count coll) (count x))
1218 (reduce
1219 #(and %1 %2)
1220 true
1221 (map #(member? %1 %2) coll x))))))
1222 ([abstract-set n]
1223 (abstract-down (repeat n abstract-set))))
1224
1225
1226
1227
1228
1229 ;-------ABSTRACT FUNCTIONS
1230 (defrecord AbstractFn
1231 [#^AbstractSet domain #^AbstractSet codomain])
1232
1233
1234 (defmethod print-method AbstractFn
1235 [o w]
1236 (print-simple
1237 (str
1238 "f:"
1239 (.glyph (:domain o))
1240 "-->"
1241 (.glyph (:codomain o))) w))
1242 #+end_src
1243
1244
1245 * COMMENT
1246 #+begin_src clojure :tangle utils.clj
1247 (ns sicm.utils)
1248
1249 ;***** GENERIC ARITHMETIC
1250 <<generic-arithmetic>>
1251
1252
1253 ;***** TUPLES AND MATRICES
1254 <<tuples>>
1255 <<tuples-2>>
1256 ;***** MATRICES
1257 <<matrices>>
1258
1259 #+end_src
1260
1261
1262