rlm@2: <?xml version="1.0" encoding="utf-8"?> rlm@2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" rlm@2: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> rlm@2: <html xmlns="http://www.w3.org/1999/xhtml" rlm@2: lang="en" xml:lang="en"> rlm@2: <head> rlm@2: <title>Building a Classical Mechanics Library in Clojure</title> rlm@2: <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> rlm@2: <meta name="generator" content="Org-mode"/> rlm@2: <meta name="generated" content="2011-08-11 04:10:36 EDT"/> rlm@2: <meta name="author" content="Dylan Holmes"/> rlm@2: <meta name="description" content=""/> rlm@2: <meta name="keywords" content=""/> rlm@2: <style type="text/css"> rlm@2: <!--/*--><![CDATA[/*><!--*/ rlm@2: html { font-family: Times, serif; font-size: 12pt; } rlm@2: .title { text-align: center; } rlm@2: .todo { color: red; } rlm@2: .done { color: green; } rlm@2: .tag { background-color: #add8e6; font-weight:normal } rlm@2: .target { } rlm@2: .timestamp { color: #bebebe; } rlm@2: .timestamp-kwd { color: #5f9ea0; } rlm@2: .right {margin-left:auto; margin-right:0px; text-align:right;} rlm@2: .left {margin-left:0px; margin-right:auto; text-align:left;} rlm@2: .center {margin-left:auto; margin-right:auto; text-align:center;} rlm@2: p.verse { margin-left: 3% } rlm@2: pre { rlm@2: border: 1pt solid #AEBDCC; rlm@2: background-color: #F3F5F7; rlm@2: padding: 5pt; rlm@2: font-family: courier, monospace; rlm@2: font-size: 90%; rlm@2: overflow:auto; rlm@2: } rlm@2: table { border-collapse: collapse; } rlm@2: td, th { vertical-align: top; } rlm@2: th.right { text-align:center; } rlm@2: th.left { text-align:center; } rlm@2: th.center { text-align:center; } rlm@2: td.right { text-align:right; } rlm@2: td.left { text-align:left; } rlm@2: td.center { text-align:center; } rlm@2: dt { font-weight: bold; } rlm@2: div.figure { padding: 0.5em; } rlm@2: div.figure p { text-align: center; } rlm@2: textarea { overflow-x: auto; } rlm@2: .linenr { font-size:smaller } rlm@2: .code-highlighted {background-color:#ffff00;} rlm@2: .org-info-js_info-navigation { border-style:none; } rlm@2: #org-info-js_console-label { font-size:10px; font-weight:bold; rlm@2: white-space:nowrap; } rlm@2: .org-info-js_search-highlight {background-color:#ffff00; color:#000000; rlm@2: font-weight:bold; } rlm@2: /*]]>*/--> rlm@2: </style> rlm@2: <link rel="stylesheet" type="text/css" href="../css/aurellem.css" /> rlm@2: <script type="text/javascript"> rlm@2: <!--/*--><![CDATA[/*><!--*/ rlm@2: function CodeHighlightOn(elem, id) rlm@2: { rlm@2: var target = document.getElementById(id); rlm@2: if(null != target) { rlm@2: elem.cacheClassElem = elem.className; rlm@2: elem.cacheClassTarget = target.className; rlm@2: target.className = "code-highlighted"; rlm@2: elem.className = "code-highlighted"; rlm@2: } rlm@2: } rlm@2: function CodeHighlightOff(elem, id) rlm@2: { rlm@2: var target = document.getElementById(id); rlm@2: if(elem.cacheClassElem) rlm@2: elem.className = elem.cacheClassElem; rlm@2: if(elem.cacheClassTarget) rlm@2: target.className = elem.cacheClassTarget; rlm@2: } rlm@2: /*]]>*///--> rlm@2: </script> rlm@2: rlm@2: </head> rlm@2: <body> rlm@2: rlm@2: <div id="content"> rlm@2: rlm@2: rlm@2: rlm@2: <div class="header"> rlm@2: <div class="float-right"> rlm@2: <!-- rlm@2: <form> rlm@2: <input type="text"/><input type="submit" value="search the blog »"/> rlm@2: </form> rlm@2: --> rlm@2: </div> rlm@2: rlm@2: <h1>aurellem <em>☉</em></h1> rlm@2: <ul class="nav"> rlm@2: <li><a href="/">read the blog »</a></li> rlm@2: <!-- li><a href="#">learn about us »</a></li--> rlm@2: </ul> rlm@2: </div> rlm@2: rlm@2: <h1 class="title">Building a Classical Mechanics Library in Clojure</h1> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: <div id="table-of-contents"> rlm@2: <h2>Table of Contents</h2> rlm@2: <div id="text-table-of-contents"> rlm@2: <ul> rlm@2: <li><a href="#sec-1">1 Useful data types </a> rlm@2: <ul> rlm@2: <li><a href="#sec-1-1">1.1 Complex numbers </a></li> rlm@2: <li><a href="#sec-1-2">1.2 Power series </a></li> rlm@2: <li><a href="#sec-1-3">1.3 Tuples and tensors </a> rlm@2: <ul> rlm@2: <li><a href="#sec-1-3-1">1.3.1 Tuples are “sequences with spin” </a></li> rlm@2: <li><a href="#sec-1-3-2">1.3.2 Matrices </a></li> rlm@2: </ul> rlm@2: </li> rlm@2: <li><a href="#sec-1-4">1.4 Generic Operations </a></li> rlm@2: </ul> rlm@2: </li> rlm@2: <li><a href="#sec-2">2 Operators and Differentiation </a> rlm@2: <ul> rlm@2: <li><a href="#sec-2-1">2.1 Operators </a></li> rlm@2: <li><a href="#sec-2-2">2.2 Differential Terms and Sequences </a></li> rlm@2: </ul> rlm@2: </li> rlm@2: </ul> rlm@2: </div> rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1" class="outline-2"> rlm@2: <h2 id="sec-1"><span class="section-number-2">1</span> Useful data types </h2> rlm@2: <div class="outline-text-2" id="text-1"> rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-1" class="outline-3"> rlm@2: <h3 id="sec-1-1"><span class="section-number-3">1.1</span> Complex numbers </h3> rlm@2: <div class="outline-text-3" id="text-1-1"> rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-2" class="outline-3"> rlm@2: <h3 id="sec-1-2"><span class="section-number-3">1.2</span> Power series </h3> rlm@2: <div class="outline-text-3" id="text-1-2"> rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-3" class="outline-3"> rlm@2: <h3 id="sec-1-3"><span class="section-number-3">1.3</span> Tuples and tensors </h3> rlm@2: <div class="outline-text-3" id="text-1-3"> rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-3-1" class="outline-4"> rlm@2: <h4 id="sec-1-3-1"><span class="section-number-4">1.3.1</span> Tuples are “sequences with spin” </h4> rlm@2: <div class="outline-text-4" id="text-1-3-1"> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'sicm.utils) rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">Let some objects have spin</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defprotocol</span> <span style="color: #f0dfaf;">Spinning</span> rlm@2: (up? [this]) rlm@2: (down? [this])) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">spin</span> rlm@2: <span style="color: #8fb28f;">"Returns the spin of the Spinning s, either :up or :down"</span> rlm@2: [<span style="color: #dfdfbf; font-weight: bold;">#^Spinning</span> s] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">cond</span> (up? s) <span style="color: #8cd0d3;">:up</span> (down? s) <span style="color: #8cd0d3;">:down</span>)) rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">DEFINITION: A tuple is a sequence with spin</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">deftype</span> <span style="color: #f0dfaf;">Tuple</span> rlm@2: [spin coll] rlm@2: rlm@2: clojure.lang.Seqable rlm@2: (<span style="color: #8cd0d3;">seq</span> [this] (<span style="color: #8cd0d3;">seq</span> (.coll this))) rlm@2: rlm@2: clojure.lang.Counted rlm@2: (<span style="color: #8cd0d3;">count</span> [this] (<span style="color: #8cd0d3;">count</span> (.coll this))) rlm@2: rlm@2: Spinning rlm@2: (up? [this] (<span style="color: #8cd0d3;">=</span> <span style="color: #8cd0d3;">::up</span> (.spin this))) rlm@2: (down? [this] (<span style="color: #8cd0d3;">=</span> <span style="color: #8cd0d3;">::down</span> (.spin this)))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">print-method</span> Tuple rlm@2: [o w] rlm@2: (<span style="color: #8cd0d3;">print-simple</span> rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (up? o) rlm@2: (<span style="color: #8cd0d3;">str</span> <span style="color: #cc9393;">"u"</span> (.coll o)) rlm@2: (<span style="color: #8cd0d3;">str</span> <span style="color: #cc9393;">"d"</span> (<span style="color: #8cd0d3;">vec</span>(.coll o)))) rlm@2: w)) rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">CONSTRUCTORS</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">up</span> rlm@2: <span style="color: #8fb28f;">"Create a new up-tuple containing the contents of coll."</span> rlm@2: [coll] rlm@2: (Tuple. <span style="color: #8cd0d3;">::up</span> coll)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">down</span> rlm@2: <span style="color: #8fb28f;">"Create a new down-tuple containing the contents of coll."</span> rlm@2: [coll] rlm@2: (Tuple. <span style="color: #8cd0d3;">::down</span> coll)) rlm@2: </pre> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-3-2" class="outline-4"> rlm@2: <h4 id="sec-1-3-2"><span class="section-number-4">1.3.2</span> Matrices </h4> rlm@2: <div class="outline-text-4" id="text-1-3-2"> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'sicm.utils) rlm@2: (<span style="color: #8cd0d3;">require</span> 'incanter.core) <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">use incanter's fast matrices</span> rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">all-equal?</span> [coll] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">empty?</span> (<span style="color: #8cd0d3;">rest</span> coll)) true rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">and</span> (<span style="color: #8cd0d3;">=</span> (<span style="color: #8cd0d3;">first</span> coll) (<span style="color: #8cd0d3;">second</span> coll)) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">recur</span> (<span style="color: #8cd0d3;">rest</span> coll))))) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defprotocol</span> <span style="color: #f0dfaf;">Matrix</span> rlm@2: (rows [matrix]) rlm@2: (cols [matrix]) rlm@2: (diagonal [matrix]) rlm@2: (trace [matrix]) rlm@2: (determinant [matrix]) rlm@2: (transpose [matrix]) rlm@2: (conjugate [matrix]) rlm@2: ) rlm@2: rlm@2: (<span style="color: #8cd0d3;">extend-protocol</span> Matrix incanter.Matrix rlm@2: (rows [rs] (<span style="color: #8cd0d3;">map</span> down (<span style="color: #8cd0d3;">apply</span> map vector (<span style="color: #8cd0d3;">apply</span> map vector rs)))) rlm@2: (cols [rs] (<span style="color: #8cd0d3;">map</span> up (<span style="color: #8cd0d3;">apply</span> map vector rs))) rlm@2: (diagonal [matrix] (incanter.core/diag matrix) ) rlm@2: (determinant [matrix] (incanter.core/det matrix)) rlm@2: (trace [matrix] (incanter.core/trace matrix)) rlm@2: (transpose [matrix] (incanter.core/trans matrix))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">count-rows</span> [matrix] rlm@2: ((<span style="color: #8cd0d3;">comp</span> count rows) matrix)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">count-cols</span> [matrix] rlm@2: ((<span style="color: #8cd0d3;">comp</span> count cols) matrix)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">square?</span> [matrix] rlm@2: (<span style="color: #8cd0d3;">=</span> (count-rows matrix) (count-cols matrix))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">identity-matrix</span> rlm@2: <span style="color: #8fb28f;">"Define a square matrix of size n-by-n with 1s along the diagonal and</span> rlm@2: <span style="color: #8fb28f;"> 0s everywhere else."</span> rlm@2: [n] rlm@2: (incanter.core/identity-matrix n)) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">matrix-by-rows</span> rlm@2: <span style="color: #8fb28f;">"Define a matrix by giving its rows."</span> rlm@2: [& rows] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> rlm@2: (<span style="color: #8cd0d3;">not</span> (all-equal? (<span style="color: #8cd0d3;">map</span> count rows))) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (Exception. <span style="color: #cc9393;">"All rows in a matrix must have the same number of elements."</span>)) rlm@2: (incanter.core/matrix (<span style="color: #8cd0d3;">vec</span> rows)))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">matrix-by-cols</span> rlm@2: <span style="color: #8fb28f;">"Define a matrix by giving its columns"</span> rlm@2: [& cols] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">not</span> (all-equal? (<span style="color: #8cd0d3;">map</span> count cols))) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (Exception. <span style="color: #cc9393;">"All columns in a matrix must have the same number of elements."</span>)) rlm@2: (incanter.core/matrix (<span style="color: #8cd0d3;">vec</span> (<span style="color: #8cd0d3;">apply</span> map vector cols))))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">identity-matrix</span> rlm@2: <span style="color: #8fb28f;">"Define a square matrix of size n-by-n with 1s along the diagonal and</span> rlm@2: <span style="color: #8fb28f;"> 0s everywhere else."</span> rlm@2: [n] rlm@2: (incanter.core/identity-matrix n)) rlm@2: rlm@2: </pre> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-1-4" class="outline-3"> rlm@2: <h3 id="sec-1-4"><span class="section-number-3">1.4</span> Generic Operations </h3> rlm@2: <div class="outline-text-3" id="text-1-4"> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'sicm.utils) rlm@2: (<span style="color: #8cd0d3;">use</span> 'clojure.contrib.generic.arithmetic rlm@2: 'clojure.contrib.generic.collection rlm@2: 'clojure.contrib.generic.functor rlm@2: 'clojure.contrib.generic.math-functions) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">numbers?</span> rlm@2: <span style="color: #8fb28f;">"Returns true if all arguments are numbers, else false."</span> rlm@2: [& xs] rlm@2: (<span style="color: #8cd0d3;">every?</span> number? xs)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">tuple-surgery</span> rlm@2: <span style="color: #8fb28f;">"Applies the function f to the items of tuple and the additional</span> rlm@2: <span style="color: #8fb28f;"> arguments, if any. Returns a Tuple of the same type as tuple."</span> rlm@2: [tuple f & xs] rlm@2: ((<span style="color: #f0dfaf; font-weight: bold;">if</span> (up? tuple) up down) rlm@2: (<span style="color: #8cd0d3;">apply</span> f (<span style="color: #8cd0d3;">seq</span> tuple) xs))) rlm@2: rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;;; </span><span style="color: #7f9f7f;">CONTRACTION collapses two compatible tuples into a number.</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">contractible?</span> rlm@2: <span style="color: #8fb28f;">"Returns true if the tuples a and b are compatible for contraction,</span> rlm@2: <span style="color: #8fb28f;"> else false. Tuples are compatible if they have the same number of</span> rlm@2: <span style="color: #8fb28f;"> components, they have opposite spins, and their elements are</span> rlm@2: <span style="color: #8fb28f;"> pairwise-compatible."</span> rlm@2: [a b] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">and</span> rlm@2: (<span style="color: #8cd0d3;">isa?</span> (<span style="color: #8cd0d3;">type</span> a) Tuple) rlm@2: (<span style="color: #8cd0d3;">isa?</span> (<span style="color: #8cd0d3;">type</span> b) Tuple) rlm@2: (<span style="color: #8cd0d3;">=</span> (<span style="color: #8cd0d3;">count</span> a) (<span style="color: #8cd0d3;">count</span> b)) rlm@2: (<span style="color: #8cd0d3;">not=</span> (spin a) (spin b)) rlm@2: rlm@2: (<span style="color: #8cd0d3;">not-any?</span> false? rlm@2: (<span style="color: #8cd0d3;">map</span> #(<span style="color: #f0dfaf; font-weight: bold;">or</span> rlm@2: (numbers? %1 %2) rlm@2: (contractible? %1 %2)) rlm@2: a b)))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">contract</span> rlm@2: <span style="color: #8fb28f;">"Contracts two tuples, returning the sum of the</span> rlm@2: <span style="color: #8fb28f;"> products of the corresponding items. Contraction is recursive on</span> rlm@2: <span style="color: #8fb28f;"> nested tuples."</span> rlm@2: [a b] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">not</span> (contractible? a b)) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> rlm@2: (Exception. <span style="color: #cc9393;">"Not compatible for contraction."</span>)) rlm@2: (<span style="color: #8cd0d3;">reduce</span> + rlm@2: (<span style="color: #8cd0d3;">map</span> rlm@2: (<span style="color: #8cd0d3;">fn</span> [x y] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (numbers? x y) rlm@2: (<span style="color: #8cd0d3;">*</span> x y) rlm@2: (contract x y))) rlm@2: a b)))) rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">conj</span> Tuple rlm@2: [tuple & xs] rlm@2: (tuple-surgery tuple #(<span style="color: #8cd0d3;">apply</span> conj % xs))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">fmap</span> Tuple rlm@2: [f tuple] rlm@2: (tuple-surgery tuple (<span style="color: #8cd0d3;">partial</span> map f))) rlm@2: rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">TODO: define Scalar, and add it to the hierarchy above Number and Complex</span> rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [Tuple Tuple] <span style="color: #708070;">; </span><span style="color: #7f9f7f;">tuple*tuple</span> rlm@2: [a b] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (contractible? a b) rlm@2: (contract a b) rlm@2: (<span style="color: #8cd0d3;">map</span> (<span style="color: #8cd0d3;">partial</span> * a) b))) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [java.lang.Number Tuple] <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">scalar * tuple</span> rlm@2: [a x] (fmap (<span style="color: #8cd0d3;">partial</span> * a) x)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [Tuple java.lang.Number] rlm@2: [x a] (<span style="color: #8cd0d3;">*</span> a x)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [java.lang.Number incanter.Matrix] <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">scalar * matrix</span> rlm@2: [x M] (incanter.core/mult x M)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [incanter.Matrix java.lang.Number] rlm@2: [M x] (<span style="color: #8cd0d3;">*</span> x M)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [incanter.Matrix incanter.Matrix] <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">matrix * matrix</span> rlm@2: [M1 M2] rlm@2: (incanter.core/mmult M1 M2)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [incanter.Matrix Tuple] <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">matrix * tuple</span> rlm@2: [M v] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #f0dfaf; font-weight: bold;">and</span> (<span style="color: #8cd0d3;">apply</span> numbers? v) (up? v)) rlm@2: (<span style="color: #8cd0d3;">*</span> M (matrix-by-cols v)) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (Exception. <span style="color: #cc9393;">"Currently, you can only multiply a matrix by a tuple of *numbers*"</span>)) rlm@2: )) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [Tuple incanter.Matrix] <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">tuple * Matrix</span> rlm@2: [v M] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #f0dfaf; font-weight: bold;">and</span> (<span style="color: #8cd0d3;">apply</span> numbers? v) (down? v)) rlm@2: (<span style="color: #8cd0d3;">*</span> (matrix-by-rows v) M) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (Exception. <span style="color: #cc9393;">"Currently, you can only multiply a matrix by a tuple of *numbers*"</span>)) rlm@2: )) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">exp</span> incanter.Matrix rlm@2: [M] rlm@2: (incanter.core/exp M)) rlm@2: rlm@2: </pre> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-2" class="outline-2"> rlm@2: <h2 id="sec-2"><span class="section-number-2">2</span> Operators and Differentiation </h2> rlm@2: <div class="outline-text-2" id="text-2"> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-2-1" class="outline-3"> rlm@2: <h3 id="sec-2-1"><span class="section-number-3">2.1</span> Operators </h3> rlm@2: <div class="outline-text-3" id="text-2-1"> rlm@2: rlm@2: rlm@2: </div> rlm@2: rlm@2: </div> rlm@2: rlm@2: <div id="outline-container-2-2" class="outline-3"> rlm@2: <h3 id="sec-2-2"><span class="section-number-3">2.2</span> Differential Terms and Sequences </h3> rlm@2: <div class="outline-text-3" id="text-2-2"> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: <pre class="src src-clojure">(<span style="color: #f0dfaf; font-weight: bold;">in-ns</span> 'sicm.utils) rlm@2: (<span style="color: #8cd0d3;">use</span> 'clojure.contrib.seq rlm@2: 'clojure.contrib.generic.arithmetic rlm@2: 'clojure.contrib.generic.collection rlm@2: 'clojure.contrib.generic.math-functions) rlm@2: rlm@2: <span style="color: #708070;">;;</span><span style="color: #7f9f7f;">∂</span> rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">DEFINITION : Differential Term</span> rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">A quantity with infinitesimal components, e.g. x, dxdy, 4dydz. The</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">coefficient of the quantity is returned by the 'coefficient' method,</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">while the sequence of differential parameters is returned by the</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">method 'partials'.</span> rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">Instead of using (potentially ambiguous) letters to denote</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">differential parameters (dx,dy,dz), we use integers. So, dxdz becomes [0 2].</span> rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">The coefficient can be any arithmetic object; the</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">partials must be a nonrepeating sorted sequence of nonnegative</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">integers.</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">deftype</span> <span style="color: #f0dfaf;">DifferentialTerm</span> [coefficient partials]) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">differential-term</span> rlm@2: <span style="color: #8fb28f;">"Make a differential term given pairs of coefficients and partials."</span> rlm@2: [coefficient partials] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #f0dfaf; font-weight: bold;">and</span> (<span style="color: #8cd0d3;">coll?</span> partials) (<span style="color: #8cd0d3;">every?</span> #(<span style="color: #f0dfaf; font-weight: bold;">and</span> (<span style="color: #8cd0d3;">integer?</span> %) (<span style="color: #8cd0d3;">not</span>(<span style="color: #8cd0d3;">neg?</span> %))) partials)) rlm@2: (DifferentialTerm. coefficient (<span style="color: #8cd0d3;">set</span> partials)) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (java.lang.IllegalArgumentException. <span style="color: #cc9393;">"Partials must be a collection of integers."</span>)))) rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">DEFINITION : Differential Sequence</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">A differential sequence is a sequence of differential terms, all with different partials.</span> rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">Internally, it is a map from the partials of each term to their coefficients.</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">deftype</span> <span style="color: #f0dfaf;">DifferentialSeq</span> rlm@2: [terms] rlm@2: <span style="color: #708070;">;;</span><span style="color: #7f9f7f;">clojure.lang.IPersistentMap</span> rlm@2: clojure.lang.Associative rlm@2: (<span style="color: #8cd0d3;">assoc</span> [this key val] rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">cons</span> (differential-term val key) terms))) rlm@2: (<span style="color: #8cd0d3;">cons</span> [this x] rlm@2: (DifferentialSeq. (<span style="color: #8cd0d3;">cons</span> x terms))) rlm@2: (containsKey [this key] rlm@2: (<span style="color: #8cd0d3;">not</span>(<span style="color: #8cd0d3;">nil?</span> (find-first #(<span style="color: #8cd0d3;">=</span> (.partials %) key) terms)))) rlm@2: (<span style="color: #8cd0d3;">count</span> [this] (<span style="color: #8cd0d3;">count</span> (.terms this))) rlm@2: (<span style="color: #8cd0d3;">empty</span> [this] (DifferentialSeq. [])) rlm@2: (entryAt [this key] rlm@2: ((<span style="color: #8cd0d3;">juxt</span> #(.partials %) #(.coefficient %)) rlm@2: (find-first #(<span style="color: #8cd0d3;">=</span> (.partials %) key) terms))) rlm@2: (<span style="color: #8cd0d3;">seq</span> [this] (<span style="color: #8cd0d3;">seq</span> (.terms this)))) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">fmap</span> DifferentialSeq rlm@2: [f dseq] rlm@2: (DifferentialSeq. (fmap f (.terms dseq)))) rlm@2: rlm@2: rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">BUILDING DIFFERENTIAL OBJECTS</span> rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">differential-seq</span> rlm@2: <span style="color: #8fb28f;">"Define a differential sequence by specifying coefficient/partials</span> rlm@2: <span style="color: #8fb28f;">pairs, which are used to create differential terms to populate the</span> rlm@2: <span style="color: #8fb28f;">sequence."</span> rlm@2: ([coefficient partials] rlm@2: (DifferentialSeq. {(<span style="color: #8cd0d3;">set</span> partials) coefficient})) rlm@2: ([coefficient partials & cps] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">odd?</span> (<span style="color: #8cd0d3;">count</span> cps)) rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">throw</span> (Exception. <span style="color: #cc9393;">"differential-seq requires an even number of terms."</span>)) rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">reduce</span> rlm@2: #(<span style="color: #8cd0d3;">assoc</span> %1 (<span style="color: #8cd0d3;">set</span> (<span style="color: #8cd0d3;">second</span> %2)) (<span style="color: #8cd0d3;">first</span> %2)) rlm@2: {(<span style="color: #8cd0d3;">set</span> partials) coefficient} rlm@2: (<span style="color: #8cd0d3;">partition</span> 2 cps)))))) rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">big-part</span> rlm@2: <span style="color: #8fb28f;">"Returns the part of the differential sequence that is finite,</span> rlm@2: <span style="color: #8fb28f;"> i.e. not infinitely small, as a differential sequence. If given a</span> rlm@2: <span style="color: #8fb28f;"> non-differential object, returns that object."</span> rlm@2: [dseq] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">not=</span> (<span style="color: #8cd0d3;">type</span> dseq) DifferentialSeq) dseq rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">let</span> [m (.terms dseq) rlm@2: keys (<span style="color: #8cd0d3;">sort-by</span> count (<span style="color: #8cd0d3;">keys</span> m)) rlm@2: smallest-var (<span style="color: #8cd0d3;">last</span> (<span style="color: #8cd0d3;">last</span> keys))] rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">reduce</span> rlm@2: #(<span style="color: #8cd0d3;">assoc</span> %1 (<span style="color: #8cd0d3;">first</span> %2) (<span style="color: #8cd0d3;">second</span> %2)) rlm@2: {} rlm@2: (<span style="color: #8cd0d3;">remove</span> #((<span style="color: #8cd0d3;">first</span> %) smallest-var) m)))))) rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">small-part</span> rlm@2: <span style="color: #8fb28f;">"Returns the part of the differential sequence that infinitely</span> rlm@2: <span style="color: #8fb28f;"> small, as a differential sequence. If given a non-differential</span> rlm@2: <span style="color: #8fb28f;"> object, returns that object."</span> rlm@2: [dseq] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">not=</span> (<span style="color: #8cd0d3;">type</span> dseq) DifferentialSeq) 0 rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">let</span> [m (.terms dseq) rlm@2: keys (<span style="color: #8cd0d3;">sort-by</span> count (<span style="color: #8cd0d3;">keys</span> m)) rlm@2: smallest-var (<span style="color: #8cd0d3;">last</span> (<span style="color: #8cd0d3;">last</span> keys))] rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">reduce</span> rlm@2: #(<span style="color: #8cd0d3;">assoc</span> %1 (<span style="color: #8cd0d3;">first</span> %2) (<span style="color: #8cd0d3;">second</span> %2)) {} rlm@2: (<span style="color: #8cd0d3;">filter</span> #((<span style="color: #8cd0d3;">first</span> %) smallest-var) m)))))) rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">cartesian-product</span> [set1 set2] rlm@2: (<span style="color: #8cd0d3;">reduce</span> concat rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">for</span> [x set1] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">for</span> [y set2] rlm@2: [x y])))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">differential-multiply</span> rlm@2: <span style="color: #8fb28f;">"Multiply two differential sequences. The square of any differential</span> rlm@2: <span style="color: #8fb28f;"> variable is zero since differential variables are infinitesimally</span> rlm@2: <span style="color: #8fb28f;"> small."</span> rlm@2: [dseq1 dseq2] rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">reduce</span> rlm@2: (<span style="color: #8cd0d3;">fn</span> [m [[vars1 coeff1] [vars2 coeff2]]] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">if</span> (<span style="color: #8cd0d3;">not</span> (<span style="color: #8cd0d3;">empty?</span> (clojure.set/<span style="color: #dfdfbf; font-weight: bold;">intersection</span> vars1 vars2))) rlm@2: m rlm@2: (<span style="color: #8cd0d3;">assoc</span> m (clojure.set/<span style="color: #dfdfbf; font-weight: bold;">union</span> vars1 vars2) (<span style="color: #8cd0d3;">*</span> coeff1 coeff2)))) rlm@2: {} rlm@2: (cartesian-product (.terms dseq1) (.terms dseq2))))) rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [DifferentialSeq DifferentialSeq] rlm@2: [dseq1 dseq2] rlm@2: (differential-multiply dseq1 dseq2)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">+</span> [DifferentialSeq DifferentialSeq] rlm@2: [dseq1 dseq2] rlm@2: (DifferentialSeq. rlm@2: (<span style="color: #8cd0d3;">merge-with</span> + (.terms dseq1) (.terms dseq2)))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [java.lang.Number DifferentialSeq] rlm@2: [x dseq] rlm@2: (fmap (<span style="color: #8cd0d3;">partial</span> * x) dseq)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">*</span> [DifferentialSeq java.lang.Number] rlm@2: [dseq x] rlm@2: (fmap (<span style="color: #8cd0d3;">partial</span> * x) dseq)) rlm@2: <span style="color: #708070;">;; </span><span style="color: #7f9f7f;">DERIVATIVES</span> rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">linear-approximator</span> rlm@2: <span style="color: #8fb28f;">"Returns an operator that linearly approximates the given function."</span> rlm@2: ([f df|dx] rlm@2: (<span style="color: #8cd0d3;">fn</span> [x] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">let</span> [big-part (big-part x) rlm@2: small-part (small-part x)] rlm@2: (<span style="color: #8cd0d3;">+</span> (fmap f big-part) rlm@2: (<span style="color: #8cd0d3;">*</span> (fmap df|dx big-part) small-part))))) rlm@2: ([f df|dx df|dy] rlm@2: (<span style="color: #8cd0d3;">fn</span> [x y] rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">let</span> [X (big-part x) rlm@2: Y (big-part y) rlm@2: DX (small-part x) rlm@2: DY (small-part y)] rlm@2: (<span style="color: #8cd0d3;">+</span> (f X Y) rlm@2: (<span style="color: #8cd0d3;">+</span> (<span style="color: #8cd0d3;">*</span> DX (df|dx X Y)) rlm@2: (<span style="color: #8cd0d3;">*</span> DY (df|dy X Y))))))) rlm@2: ) rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">D</span>[f] rlm@2: (<span style="color: #8cd0d3;">fn</span>[x] rlm@2: (f (differential-seq x [] 1 [0])))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defn</span> <span style="color: #f0dfaf;">d</span>[f partials] rlm@2: (<span style="color: #8cd0d3;">fn</span> [x] rlm@2: (<span style="color: #8cd0d3;">get</span> rlm@2: (.terms ((D f)x)) rlm@2: (<span style="color: #8cd0d3;">set</span> partials) rlm@2: 0 rlm@2: ))) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">exp</span> DifferentialSeq [x] rlm@2: ((linear-approximator exp exp) x)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">sin</span> DifferentialSeq rlm@2: [x] rlm@2: ((linear-approximator sin cos) x)) rlm@2: rlm@2: (<span style="color: #f0dfaf; font-weight: bold;">defmethod</span> <span style="color: #f0dfaf;">cos</span> DifferentialSeq rlm@2: [x] rlm@2: ((linear-approximator cos #(<span style="color: #8cd0d3;">-</span> (sin %))) x)) rlm@2: rlm@2: rlm@2: rlm@2: </pre> rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: rlm@2: </div> rlm@2: </div> rlm@2: </div> rlm@2: <div id="postamble"> rlm@2: <p class="date">Date: 2011-08-11 04:10:36 EDT</p> rlm@2: <p class="author">Author: Dylan Holmes</p> rlm@2: <p class="creator">Org version 7.6 with Emacs version 23</p> rlm@2: <a href="http://validator.w3.org/check?uri=referer">Validate XHTML 1.0</a> rlm@2: </div> rlm@2: </div> rlm@2: </body> rlm@2: </html>