Mercurial > dylan
diff sicm/utils.org @ 2:b4de894a1e2e
initial import
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Fri, 28 Oct 2011 00:03:05 -0700 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/sicm/utils.org Fri Oct 28 00:03:05 2011 -0700 1.3 @@ -0,0 +1,690 @@ 1.4 +#+TITLE: Building a Classical Mechanics Library in Clojure 1.5 +#+author: Dylan Holmes 1.6 +#+EMAIL: rlm@mit.edu 1.7 +#+MATHJAX: align:"left" mathml:t path:"../MathJax/MathJax.js" 1.8 +#+STYLE: <link rel="stylesheet" type="text/css" href="../css/aurellem.css" /> 1.9 +#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t 1.10 +#+SETUPFILE: ../templates/level-0.org 1.11 +#+INCLUDE: ../templates/level-0.org 1.12 +#+BABEL: :noweb yes :results silent 1.13 + 1.14 +* Useful data types 1.15 + 1.16 +** Complex numbers 1.17 + 1.18 +** Power series 1.19 + 1.20 +** Tuples and tensors 1.21 + 1.22 +*** Tuples are \ldquo{}sequences with spin\rdquo{} 1.23 + 1.24 +#+srcname: tuples 1.25 +#+begin_src clojure 1.26 +(in-ns 'sicm.utils) 1.27 + 1.28 +;; Let some objects have spin 1.29 + 1.30 +(defprotocol Spinning 1.31 + (up? [this]) 1.32 + (down? [this])) 1.33 + 1.34 +(defn spin 1.35 + "Returns the spin of the Spinning s, either :up or :down" 1.36 + [#^Spinning s] 1.37 + (cond (up? s) :up (down? s) :down)) 1.38 + 1.39 + 1.40 +;; DEFINITION: A tuple is a sequence with spin 1.41 + 1.42 +(deftype Tuple 1.43 + [spin coll] 1.44 + 1.45 + clojure.lang.Seqable 1.46 + (seq [this] (seq (.coll this))) 1.47 + 1.48 + clojure.lang.Counted 1.49 + (count [this] (count (.coll this))) 1.50 + 1.51 + Spinning 1.52 + (up? [this] (= ::up (.spin this))) 1.53 + (down? [this] (= ::down (.spin this)))) 1.54 + 1.55 +(defmethod print-method Tuple 1.56 + [o w] 1.57 + (print-simple 1.58 + (if (up? o) 1.59 + (str "u" (.coll o)) 1.60 + (str "d" (vec(.coll o)))) 1.61 + w)) 1.62 + 1.63 +(def tuple? #(= (type %) Tuple)) 1.64 + 1.65 +;; CONSTRUCTORS 1.66 + 1.67 +(defn up 1.68 + "Create a new up-tuple containing the contents of coll." 1.69 + [coll] 1.70 + (Tuple. ::up coll)) 1.71 + 1.72 +(defn down 1.73 + "Create a new down-tuple containing the contents of coll." 1.74 + [coll] 1.75 + (Tuple. ::down coll)) 1.76 + 1.77 +(defn same-spin 1.78 + "Creates a tuple which has the same spin as tuple and which contains 1.79 +the contents of coll." 1.80 + [tuple coll] 1.81 + (if (up? tuple) 1.82 + (up coll) 1.83 + (down coll))) 1.84 + 1.85 +(defn opposite-spin 1.86 + "Create a tuple which has opposite spin to tuple and which contains 1.87 +the contents of coll." 1.88 + [tuple coll] 1.89 + (if (up? tuple) 1.90 + (down coll) 1.91 + (up coll))) 1.92 +#+end_src 1.93 + 1.94 + 1.95 + 1.96 +*** Matrices 1.97 +#+srcname:matrices 1.98 +#+begin_src clojure 1.99 +(in-ns 'sicm.utils) 1.100 +(require 'incanter.core) ;; use incanter's fast matrices 1.101 + 1.102 + 1.103 +(defn all-equal? [coll] 1.104 + (if (empty? (rest coll)) true 1.105 + (and (= (first coll) (second coll)) 1.106 + (recur (rest coll))))) 1.107 + 1.108 + 1.109 +(defprotocol Matrix 1.110 + (rows [matrix]) 1.111 + (cols [matrix]) 1.112 + (diagonal [matrix]) 1.113 + (trace [matrix]) 1.114 + (determinant [matrix]) 1.115 + (transpose [matrix]) 1.116 + (conjugate [matrix]) 1.117 +) 1.118 + 1.119 +(extend-protocol Matrix incanter.Matrix 1.120 + (rows [rs] (map down (apply map vector (apply map vector rs)))) 1.121 + (cols [rs] (map up (apply map vector rs))) 1.122 + (diagonal [matrix] (incanter.core/diag matrix) ) 1.123 + (determinant [matrix] (incanter.core/det matrix)) 1.124 + (trace [matrix] (incanter.core/trace matrix)) 1.125 + (transpose [matrix] (incanter.core/trans matrix))) 1.126 + 1.127 +(defn count-rows [matrix] 1.128 + ((comp count rows) matrix)) 1.129 + 1.130 +(defn count-cols [matrix] 1.131 + ((comp count cols) matrix)) 1.132 + 1.133 +(defn square? [matrix] 1.134 + (= (count-rows matrix) (count-cols matrix))) 1.135 + 1.136 +(defn identity-matrix 1.137 + "Define a square matrix of size n-by-n with 1s along the diagonal and 1.138 + 0s everywhere else." 1.139 + [n] 1.140 + (incanter.core/identity-matrix n)) 1.141 + 1.142 + 1.143 +(defn matrix-by-rows 1.144 + "Define a matrix by giving its rows." 1.145 + [& rows] 1.146 + (if 1.147 + (not (all-equal? (map count rows))) 1.148 + (throw (Exception. "All rows in a matrix must have the same number of elements.")) 1.149 + (incanter.core/matrix (vec rows)))) 1.150 + 1.151 +(defn matrix-by-cols 1.152 + "Define a matrix by giving its columns" 1.153 + [& cols] 1.154 + (if (not (all-equal? (map count cols))) 1.155 + (throw (Exception. "All columns in a matrix must have the same number of elements.")) 1.156 + (incanter.core/matrix (vec (apply map vector cols))))) 1.157 + 1.158 +(defn identity-matrix 1.159 + "Define a square matrix of size n-by-n with 1s along the diagonal and 1.160 + 0s everywhere else." 1.161 + [n] 1.162 + (incanter.core/identity-matrix n)) 1.163 + 1.164 +#+end_src 1.165 + 1.166 +** Generic Operations 1.167 +#+srcname:arith-tuple 1.168 +#+begin_src clojure 1.169 +(in-ns 'sicm.utils) 1.170 +(use 'clojure.contrib.generic.arithmetic 1.171 + 'clojure.contrib.generic.collection 1.172 + 'clojure.contrib.generic.functor 1.173 + 'clojure.contrib.generic.math-functions) 1.174 + 1.175 +(defn numbers? 1.176 + "Returns true if all arguments are numbers, else false." 1.177 + [& xs] 1.178 + (every? number? xs)) 1.179 + 1.180 +(defn tuple-surgery 1.181 + "Applies the function f to the items of tuple and the additional 1.182 + arguments, if any. Returns a Tuple of the same type as tuple." 1.183 + [tuple f & xs] 1.184 + ((if (up? tuple) up down) 1.185 + (apply f (seq tuple) xs))) 1.186 + 1.187 + 1.188 + 1.189 +;;; CONTRACTION collapses two compatible tuples into a number. 1.190 + 1.191 +(defn contractible? 1.192 + "Returns true if the tuples a and b are compatible for contraction, 1.193 + else false. Tuples are compatible if they have the same number of 1.194 + components, they have opposite spins, and their elements are 1.195 + pairwise-compatible." 1.196 + [a b] 1.197 + (and 1.198 + (isa? (type a) Tuple) 1.199 + (isa? (type b) Tuple) 1.200 + (= (count a) (count b)) 1.201 + (not= (spin a) (spin b)) 1.202 + 1.203 + (not-any? false? 1.204 + (map #(or 1.205 + (numbers? %1 %2) 1.206 + (contractible? %1 %2)) 1.207 + a b)))) 1.208 + 1.209 +(defn contract 1.210 + "Contracts two tuples, returning the sum of the 1.211 + products of the corresponding items. Contraction is recursive on 1.212 + nested tuples." 1.213 + [a b] 1.214 + (if (not (contractible? a b)) 1.215 + (throw 1.216 + (Exception. "Not compatible for contraction.")) 1.217 + (reduce + 1.218 + (map 1.219 + (fn [x y] 1.220 + (if (numbers? x y) 1.221 + (* x y) 1.222 + (contract x y))) 1.223 + a b)))) 1.224 + 1.225 + 1.226 + 1.227 + 1.228 + 1.229 +(defmethod conj Tuple 1.230 + [tuple & xs] 1.231 + (tuple-surgery tuple #(apply conj % xs))) 1.232 + 1.233 +(defmethod fmap Tuple 1.234 + [f tuple] 1.235 + (tuple-surgery tuple (partial map f))) 1.236 + 1.237 + 1.238 + 1.239 +;; TODO: define Scalar, and add it to the hierarchy above Number and Complex 1.240 + 1.241 + 1.242 +(defmethod * [Tuple Tuple] ; tuple*tuple 1.243 + [a b] 1.244 + (if (contractible? a b) 1.245 + (contract a b) 1.246 + (map (partial * a) b))) 1.247 + 1.248 + 1.249 +(defmethod * [java.lang.Number Tuple] ;; scalar * tuple 1.250 + [a x] (fmap (partial * a) x)) 1.251 + 1.252 +(defmethod * [Tuple java.lang.Number] 1.253 + [x a] (* a x)) 1.254 + 1.255 +(defmethod * [java.lang.Number incanter.Matrix] ;; scalar * matrix 1.256 + [x M] (incanter.core/mult x M)) 1.257 + 1.258 +(defmethod * [incanter.Matrix java.lang.Number] 1.259 + [M x] (* x M)) 1.260 + 1.261 +(defmethod * [incanter.Matrix incanter.Matrix] ;; matrix * matrix 1.262 + [M1 M2] 1.263 + (incanter.core/mmult M1 M2)) 1.264 + 1.265 +(defmethod * [incanter.Matrix Tuple] ;; matrix * tuple 1.266 + [M v] 1.267 + (if (and (apply numbers? v) (up? v)) 1.268 + (* M (matrix-by-cols v)) 1.269 + (throw (Exception. "Currently, you can only multiply a matrix by a tuple of *numbers*")) 1.270 + )) 1.271 + 1.272 +(defmethod * [Tuple incanter.Matrix] ;; tuple * Matrix 1.273 + [v M] 1.274 + (if (and (apply numbers? v) (down? v)) 1.275 + (* (matrix-by-rows v) M) 1.276 + (throw (Exception. "Currently, you can only multiply a matrix by a tuple of *numbers*")) 1.277 + )) 1.278 + 1.279 + 1.280 +(defmethod exp incanter.Matrix 1.281 + [M] 1.282 + (incanter.core/exp M)) 1.283 + 1.284 +#+end_src 1.285 + 1.286 +* Operators and Differentiation 1.287 +** Operators 1.288 +#+scrname: operators 1.289 +#+begin_src clojure 1.290 +(in-ns 'sicm.utils) 1.291 +(use 'clojure.contrib.seq 1.292 + 'clojure.contrib.generic.arithmetic 1.293 + 'clojure.contrib.generic.collection 1.294 + 'clojure.contrib.generic.math-functions) 1.295 + 1.296 +(defmethod + [clojure.lang.IFn clojure.lang.IFn] 1.297 + [f g] 1.298 + (fn [& args] 1.299 + (+ (apply f args) (apply g args)))) 1.300 + 1.301 +(defmethod * [clojure.lang.IFn clojure.lang.IFn] 1.302 + [f g] 1.303 + (fn [& args] 1.304 + (* (apply f args) (apply g args)))) 1.305 + 1.306 +(defmethod / [clojure.lang.IFn java.lang.Number] 1.307 + [f x] 1.308 + (fn [& args] 1.309 + (/ (apply f args) x))) 1.310 + 1.311 + 1.312 +(defmethod - [clojure.lang.IFn] 1.313 + [f] 1.314 + (fn [& args] 1.315 + (- (apply f args)))) 1.316 + 1.317 +(defmethod - [clojure.lang.IFn clojure.lang.IFn] 1.318 + [f g] 1.319 + (fn [& args] 1.320 + (- (apply f args) (apply g args)))) 1.321 + 1.322 +(defmethod pow [clojure.lang.IFn java.lang.Number] 1.323 + [f x] 1.324 + (fn [& args] 1.325 + (pow (apply f args) x))) 1.326 + 1.327 + 1.328 +(defmethod + [java.lang.Number clojure.lang.IFn] 1.329 + [x f] 1.330 + (fn [& args] 1.331 + (+ x (apply f args)))) 1.332 + 1.333 +(defmethod * [java.lang.Number clojure.lang.IFn] 1.334 + [x f] 1.335 + (fn [& args] 1.336 + (* x (apply f args)))) 1.337 + 1.338 +(defmethod * [clojure.lang.IFn java.lang.Number] 1.339 + [f x] 1.340 + (* x f)) 1.341 +(defmethod + [clojure.lang.IFn java.lang.Number] 1.342 + [f x] 1.343 + (+ x f)) 1.344 + 1.345 +#+end_src 1.346 + 1.347 +** Differential Terms and Sequences 1.348 +#+srcname: differential 1.349 +#+begin_src clojure 1.350 +(in-ns 'sicm.utils) 1.351 +(use 'clojure.contrib.seq 1.352 + 'clojure.contrib.generic.arithmetic 1.353 + 'clojure.contrib.generic.collection 1.354 + 'clojure.contrib.generic.math-functions) 1.355 + 1.356 +;;∂ 1.357 + 1.358 +;; DEFINITION : Differential Term 1.359 + 1.360 +;; A quantity with infinitesimal components, e.g. x, dxdy, 4dydz. The 1.361 +;; coefficient of the quantity is returned by the 'coefficient' method, 1.362 +;; while the sequence of differential parameters is returned by the 1.363 +;; method 'partials'. 1.364 + 1.365 +;; Instead of using (potentially ambiguous) letters to denote 1.366 +;; differential parameters (dx,dy,dz), we use integers. So, dxdz becomes [0 2]. 1.367 + 1.368 +;; The coefficient can be any arithmetic object; the 1.369 +;; partials must be a nonrepeating sorted sequence of nonnegative 1.370 +;; integers. 1.371 + 1.372 +;; (deftype DifferentialTerm [coefficient partials]) 1.373 + 1.374 +;; (defn differential-term 1.375 +;; "Make a differential term from a coefficient and list of partials." 1.376 +;; [coefficient partials] 1.377 +;; (if (and (coll? partials) (every? #(and (integer? %) (not(neg? %))) partials)) 1.378 +;; (DifferentialTerm. coefficient (set partials)) 1.379 +;; (throw (java.lang.IllegalArgumentException. "Partials must be a collection of integers.")))) 1.380 + 1.381 + 1.382 +;; DEFINITION : Differential Sequence 1.383 +;; A differential sequence is a sequence of differential terms, all with different partials. 1.384 +;; Internally, it is a map from the partials of each term to their coefficients. 1.385 + 1.386 +(deftype DifferentialSeq 1.387 + [terms] 1.388 + ;;clojure.lang.IPersistentMap 1.389 + clojure.lang.Associative 1.390 + (assoc [this key val] 1.391 + (DifferentialSeq. 1.392 + (cons (differential-term val key) terms))) 1.393 + (cons [this x] 1.394 + (DifferentialSeq. (cons x terms))) 1.395 + (containsKey [this key] 1.396 + (not(nil? (find-first #(= (.partials %) key) terms)))) 1.397 + (count [this] (count (.terms this))) 1.398 + (empty [this] (DifferentialSeq. [])) 1.399 + (entryAt [this key] 1.400 + ((juxt #(.partials %) #(.coefficient %)) 1.401 + (find-first #(= (.partials %) key) terms))) 1.402 + (seq [this] (seq (.terms this)))) 1.403 + 1.404 +(def differential? #(= (type %) DifferentialSeq)) 1.405 + 1.406 +(defn zeroth-order? 1.407 + "Returns true if the differential sequence has at most a constant term." 1.408 + [dseq] 1.409 + (and 1.410 + (differential? dseq) 1.411 + (every? 1.412 + #(= #{} %) 1.413 + (keys (.terms dseq))))) 1.414 + 1.415 +(defmethod fmap DifferentialSeq 1.416 + [f dseq] 1.417 + (DifferentialSeq. 1.418 + (fmap f (.terms dseq)))) 1.419 + 1.420 + 1.421 + 1.422 + 1.423 +;; BUILDING DIFFERENTIAL OBJECTS 1.424 + 1.425 +(defn differential-seq 1.426 + "Define a differential sequence by specifying an alternating 1.427 +sequence of coefficients and lists of partials." 1.428 + ([coefficient partials] 1.429 + (DifferentialSeq. {(set partials) coefficient})) 1.430 + ([coefficient partials & cps] 1.431 + (if (odd? (count cps)) 1.432 + (throw (Exception. "differential-seq requires an even number of terms.")) 1.433 + (DifferentialSeq. 1.434 + (reduce 1.435 + #(assoc %1 (set (second %2)) (first %2)) 1.436 + {(set partials) coefficient} 1.437 + (partition 2 cps)))))) 1.438 + 1.439 + 1.440 + 1.441 +(defn big-part 1.442 + "Returns the part of the differential sequence that is finite, 1.443 + i.e. not infinitely small. If the sequence is zeroth-order, returns 1.444 + the coefficient of the zeroth-order term instead. " 1.445 + [dseq] 1.446 + (if (zeroth-order? dseq) (get (.terms dseq) #{}) 1.447 + (let [m (.terms dseq) 1.448 + keys (sort-by count (keys m)) 1.449 + smallest-var (last (last keys))] 1.450 + (DifferentialSeq. 1.451 + (reduce 1.452 + #(assoc %1 (first %2) (second %2)) 1.453 + {} 1.454 + (remove #((first %) smallest-var) m)))))) 1.455 + 1.456 + 1.457 +(defn small-part 1.458 + "Returns the part of the differential sequence that infinitely 1.459 + small. If the sequence is zeroth-order, returns zero." 1.460 + [dseq] 1.461 + (if (zeroth-order? dseq) 0 1.462 + (let [m (.terms dseq) 1.463 + keys (sort-by count (keys m)) 1.464 + smallest-var (last (last keys))] 1.465 + (DifferentialSeq. 1.466 + (reduce 1.467 + #(assoc %1 (first %2) (second %2)) {} 1.468 + (filter #((first %) smallest-var) m)))))) 1.469 + 1.470 + 1.471 + 1.472 +(defn cartesian-product [set1 set2] 1.473 + (reduce concat 1.474 + (for [x set1] 1.475 + (for [y set2] 1.476 + [x y])))) 1.477 + 1.478 +(defn nth-subset [n] 1.479 + (if (zero? n) [] 1.480 + (let [lg2 #(/ (log %) (log 2)) 1.481 + k (int(java.lang.Math/floor (lg2 n))) 1.482 + ] 1.483 + (cons k 1.484 + (nth-subset (- n (pow 2 k))))))) 1.485 + 1.486 +(def all-partials 1.487 + (lazy-seq (map nth-subset (range)))) 1.488 + 1.489 + 1.490 +(defn differential-multiply 1.491 + "Multiply two differential sequences. The square of any differential 1.492 + variable is zero since differential variables are infinitesimally 1.493 + small." 1.494 + [dseq1 dseq2] 1.495 + (DifferentialSeq. 1.496 + (reduce 1.497 + (fn [m [[vars1 coeff1] [vars2 coeff2]]] 1.498 + (if (not (empty? (clojure.set/intersection vars1 vars2))) 1.499 + m 1.500 + (assoc m (clojure.set/union vars1 vars2) (* coeff1 coeff2)))) 1.501 + {} 1.502 + (cartesian-product (.terms dseq1) (.terms dseq2))))) 1.503 + 1.504 + 1.505 + 1.506 +(defmethod * [DifferentialSeq DifferentialSeq] 1.507 + [dseq1 dseq2] 1.508 + (differential-multiply dseq1 dseq2)) 1.509 + 1.510 +(defmethod + [DifferentialSeq DifferentialSeq] 1.511 + [dseq1 dseq2] 1.512 + (DifferentialSeq. 1.513 + (merge-with + (.terms dseq1) (.terms dseq2)))) 1.514 + 1.515 +(defmethod * [java.lang.Number DifferentialSeq] 1.516 + [x dseq] 1.517 + (fmap (partial * x) dseq)) 1.518 + 1.519 +(defmethod * [DifferentialSeq java.lang.Number] 1.520 + [dseq x] 1.521 + (fmap (partial * x) dseq)) 1.522 + 1.523 +(defmethod + [java.lang.Number DifferentialSeq] 1.524 + [x dseq] 1.525 + (+ (differential-seq x []) dseq)) 1.526 +(defmethod + [DifferentialSeq java.lang.Number] 1.527 + [dseq x] 1.528 + (+ dseq (differential-seq x []))) 1.529 + 1.530 +(defmethod - DifferentialSeq 1.531 + [x] 1.532 + (fmap - x)) 1.533 + 1.534 + 1.535 +;; DERIVATIVES 1.536 + 1.537 + 1.538 + 1.539 +(defn linear-approximator 1.540 + "Returns an operator that linearly approximates the given function." 1.541 + ([f df|dx] 1.542 + (fn [x] 1.543 + (let [big-part (big-part x) 1.544 + small-part (small-part x)] 1.545 + ;; f(x+dx) ~= f(x) + f'(x)dx 1.546 + (+ (f big-part) 1.547 + (* (df|dx big-part) small-part) 1.548 + )))) 1.549 + 1.550 + ([f df|dx df|dy] 1.551 + (fn [x y] 1.552 + (let [X (big-part x) 1.553 + Y (big-part y) 1.554 + DX (small-part x) 1.555 + DY (small-part y)] 1.556 + (+ (f X Y) 1.557 + (* DX (f df|dx X Y)) 1.558 + (* DY (f df|dy X Y))))))) 1.559 + 1.560 + 1.561 + 1.562 + 1.563 + 1.564 +(defn D[f] 1.565 + (fn[x] (f (+ x (differential-seq 1 [0] 1 [1] 1 [2]))))) 1.566 + 1.567 +(defn d[partials f] 1.568 + (fn [x] 1.569 + (get 1.570 + (.terms ((D f)x)) 1.571 + (set partials) 1.572 + 0 1.573 + ))) 1.574 + 1.575 +(defmethod exp DifferentialSeq [x] 1.576 + ((linear-approximator exp exp) x)) 1.577 + 1.578 +(defmethod sin DifferentialSeq 1.579 + [x] 1.580 + ((linear-approximator sin cos) x)) 1.581 + 1.582 +(defmethod cos DifferentialSeq 1.583 + [x] 1.584 + ((linear-approximator cos #(- (sin %))) x)) 1.585 + 1.586 +(defmethod log DifferentialSeq 1.587 + [x] 1.588 + ((linear-approximator log (fn [x] (/ x)) ) x)) 1.589 + 1.590 +(defmethod / [DifferentialSeq DifferentialSeq] 1.591 + [x y] 1.592 + ((linear-approximator / 1.593 + (fn [x y] (/ 1 y)) 1.594 + (fn [x y] (- (/ x (* y y))))) 1.595 + x y)) 1.596 + 1.597 +#+end_src 1.598 + 1.599 + 1.600 + 1.601 +* Derivatives Revisited 1.602 +#+begin_src clojure 1.603 +(in-ns 'sicm.utils) 1.604 +(use 'clojure.contrib.seq 1.605 + 'clojure.contrib.generic.arithmetic 1.606 + 'clojure.contrib.generic.collection 1.607 + 'clojure.contrib.generic.math-functions) 1.608 + 1.609 +(defn replace-in 1.610 + "Replaces the nth item in coll with the given item. If n is larger 1.611 + than the size of coll, adds n to the end of the collection." 1.612 + [coll n item] 1.613 + (concat 1.614 + (take n coll) 1.615 + [item] 1.616 + (drop (inc n) coll))) 1.617 + 1.618 +(defn euclidean-structure [f partials] 1.619 + (fn sd[g v] 1.620 + (cond 1.621 + (tuple? v) 1.622 + (opposite-spin 1.623 + v 1.624 + (map 1.625 + (fn [n] 1.626 + (sd (fn [xn] 1.627 + (g 1.628 + (same-spin v 1.629 + (replace-in v n xn)))) 1.630 + (nth v n))) 1.631 + (range (count v))))))) 1.632 + 1.633 + 1.634 + 1.635 + 1.636 +#+end_src 1.637 + 1.638 + 1.639 +* Symbolic Quantities 1.640 + 1.641 +#+srcname: symbolic 1.642 +#+begin_src clojure 1.643 +(in-ns 'sicm.utils) 1.644 +(use 'clojure.contrib.generic.arithmetic 1.645 + 'clojure.contrib.generic.math-functions) 1.646 + 1.647 +(deftype Symbolic 1.648 + [type 1.649 + expression]) 1.650 + 1.651 +(defn print-expression [s] 1.652 + (print (.expression s))) 1.653 + 1.654 +(defn symbolic-number 1.655 + [symbol] 1.656 + (Symbolic. java.lang.Number symbol)) 1.657 + 1.658 +(defn simplify-expression [s] 1.659 + (let [e (.expression s)] 1.660 + (cond 1.661 + (not(list? e)) e 1.662 + (= (first e) '+) 1.663 +) 1.664 + 1.665 + 1.666 + 1.667 +(defmethod + [Symbolic Symbolic] 1.668 + [x y] 1.669 + (Symbolic. (.type x) (list '+ (.expression x) (.expression y)))) 1.670 + 1.671 +(defmethod + [Symbolic java.lang.Number] 1.672 + [s x] 1.673 + (if (zero? x) 1.674 + s 1.675 + (Symbolic. (.type s) (list '+ (.expression s) x)))) 1.676 + 1.677 +(defmethod sin Symbolic 1.678 + [s] 1.679 + (Symbolic. (.type s) (list 'sin (.expression s)))) 1.680 + 1.681 +#+end_src 1.682 + 1.683 +* COMMENT To-be-tangled Source 1.684 +#+begin_src clojure :tangle utils.clj 1.685 +(ns sicm.utils) 1.686 + 1.687 +<<tuples>> 1.688 +<<matrices>> 1.689 +<<arith-tuple>> 1.690 + 1.691 +<<differential>> 1.692 +#+end_src 1.693 +